Salome HOME
23072: [CEA 1500] Split biquadratic elements into linear elements
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 // Copyright (C) 2007-2015  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_FaceOfNodes.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_EdgePosition.hxx"
32 #include "SMDS_FacePosition.hxx"
33 #include "SMDS_SpacePosition.hxx"
34 #include "SMDS_MeshGroup.hxx"
35 #include "SMDS_LinearEdge.hxx"
36 #include "SMDS_Downward.hxx"
37 #include "SMDS_SetIterator.hxx"
38
39 #include "SMESHDS_Group.hxx"
40 #include "SMESHDS_Mesh.hxx"
41
42 #include "SMESH_Algo.hxx"
43 #include "SMESH_ControlsDef.hxx"
44 #include "SMESH_Group.hxx"
45 #include "SMESH_MeshAlgos.hxx"
46 #include "SMESH_MesherHelper.hxx"
47 #include "SMESH_OctreeNode.hxx"
48 #include "SMESH_subMesh.hxx"
49
50 #include <Basics_OCCTVersion.hxx>
51
52 #include "utilities.h"
53 #include "chrono.hxx"
54
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepBuilderAPI_MakeEdge.hxx>
57 #include <BRepClass3d_SolidClassifier.hxx>
58 #include <BRep_Tool.hxx>
59 #include <ElCLib.hxx>
60 #include <Extrema_GenExtPS.hxx>
61 #include <Extrema_POnCurv.hxx>
62 #include <Extrema_POnSurf.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAdaptor_Surface.hxx>
65 #include <Geom_Curve.hxx>
66 #include <Geom_Surface.hxx>
67 #include <Precision.hxx>
68 #include <TColStd_ListOfInteger.hxx>
69 #include <TopAbs_State.hxx>
70 #include <TopExp.hxx>
71 #include <TopExp_Explorer.hxx>
72 #include <TopTools_ListIteratorOfListOfShape.hxx>
73 #include <TopTools_ListOfShape.hxx>
74 #include <TopTools_SequenceOfShape.hxx>
75 #include <TopoDS.hxx>
76 #include <TopoDS_Face.hxx>
77 #include <TopoDS_Solid.hxx>
78 #include <gp.hxx>
79 #include <gp_Ax1.hxx>
80 #include <gp_Dir.hxx>
81 #include <gp_Lin.hxx>
82 #include <gp_Pln.hxx>
83 #include <gp_Trsf.hxx>
84 #include <gp_Vec.hxx>
85 #include <gp_XY.hxx>
86 #include <gp_XYZ.hxx>
87
88 #include <cmath>
89
90 #include <map>
91 #include <set>
92 #include <numeric>
93 #include <limits>
94 #include <algorithm>
95 #include <sstream>
96
97 #include <boost/tuple/tuple.hpp>
98
99 #include <Standard_Failure.hxx>
100 #include <Standard_ErrorHandler.hxx>
101
102 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
103
104 using namespace std;
105 using namespace SMESH::Controls;
106
107 namespace
108 {
109   template < class ELEM_SET >
110   SMDS_ElemIteratorPtr elemSetIterator( const ELEM_SET& elements )
111   {
112     typedef SMDS_SetIterator
113       < SMDS_pElement, typename ELEM_SET::const_iterator> TSetIterator;
114     return SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
115   }
116 }
117
118 //=======================================================================
119 //function : SMESH_MeshEditor
120 //purpose  :
121 //=======================================================================
122
123 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
124   :myMesh( theMesh ) // theMesh may be NULL
125 {
126 }
127
128 //================================================================================
129 /*!
130  * \brief Clears myLastCreatedNodes and myLastCreatedElems
131  */
132 //================================================================================
133
134 void SMESH_MeshEditor::ClearLastCreated()
135 {
136   myLastCreatedNodes.Clear();
137   myLastCreatedElems.Clear();
138 }
139
140 //================================================================================
141 /*!
142  * \brief Initializes members by an existing element
143  *  \param [in] elem - the source element
144  *  \param [in] basicOnly - if true, does not set additional data of Ball and Polyhedron
145  */
146 //================================================================================
147
148 SMESH_MeshEditor::ElemFeatures&
149 SMESH_MeshEditor::ElemFeatures::Init( const SMDS_MeshElement* elem, bool basicOnly )
150 {
151   if ( elem )
152   {
153     myType = elem->GetType();
154     if ( myType == SMDSAbs_Face || myType == SMDSAbs_Volume )
155     {
156       myIsPoly = elem->IsPoly();
157       if ( myIsPoly )
158       {
159         myIsQuad = elem->IsQuadratic();
160         if ( myType == SMDSAbs_Volume && !basicOnly )
161         {
162           vector<int > quant = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
163           myPolyhedQuantities.swap( quant );
164         }
165       }
166     }
167     else if ( myType == SMDSAbs_Ball && !basicOnly )
168     {
169       myBallDiameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
170     }
171   }
172   return *this;
173 }
174
175 //=======================================================================
176 /*!
177  * \brief Add element
178  */
179 //=======================================================================
180
181 SMDS_MeshElement*
182 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
183                              const ElemFeatures&                  features)
184 {
185   SMDS_MeshElement* e = 0;
186   int nbnode = node.size();
187   SMESHDS_Mesh* mesh = GetMeshDS();
188   const int ID = features.myID;
189
190   switch ( features.myType ) {
191   case SMDSAbs_Face:
192     if ( !features.myIsPoly ) {
193       if      (nbnode == 3) {
194         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
195         else           e = mesh->AddFace      (node[0], node[1], node[2] );
196       }
197       else if (nbnode == 4) {
198         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
199         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
200       }
201       else if (nbnode == 6) {
202         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
203                                                node[4], node[5], ID);
204         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
205                                                node[4], node[5] );
206       }
207       else if (nbnode == 7) {
208         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
209                                                node[4], node[5], node[6], ID);
210         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
211                                                node[4], node[5], node[6] );
212       }
213       else if (nbnode == 8) {
214         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
215                                                node[4], node[5], node[6], node[7], ID);
216         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
217                                                node[4], node[5], node[6], node[7] );
218       }
219       else if (nbnode == 9) {
220         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
221                                                node[4], node[5], node[6], node[7], node[8], ID);
222         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
223                                                node[4], node[5], node[6], node[7], node[8] );
224       }
225     }
226     else if ( !features.myIsQuad )
227     {
228       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
229       else           e = mesh->AddPolygonalFace      (node    );
230     }
231     else if ( nbnode % 2 == 0 ) // just a protection
232     {
233       if ( ID >= 1 ) e = mesh->AddQuadPolygonalFaceWithID(node, ID);
234       else           e = mesh->AddQuadPolygonalFace      (node    );
235     }
236     break;
237
238   case SMDSAbs_Volume:
239     if ( !features.myIsPoly ) {
240       if      (nbnode == 4) {
241         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
242         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
243       }
244       else if (nbnode == 5) {
245         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
246                                                  node[4], ID);
247         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
248                                                  node[4] );
249       }
250       else if (nbnode == 6) {
251         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
252                                                  node[4], node[5], ID);
253         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
254                                                  node[4], node[5] );
255       }
256       else if (nbnode == 8) {
257         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
258                                                  node[4], node[5], node[6], node[7], ID);
259         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
260                                                  node[4], node[5], node[6], node[7] );
261       }
262       else if (nbnode == 10) {
263         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
264                                                  node[4], node[5], node[6], node[7],
265                                                  node[8], node[9], ID);
266         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
267                                                  node[4], node[5], node[6], node[7],
268                                                  node[8], node[9] );
269       }
270       else if (nbnode == 12) {
271         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
272                                                  node[4], node[5], node[6], node[7],
273                                                  node[8], node[9], node[10], node[11], ID);
274         else           e = mesh->AddVolume      (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] );
277       }
278       else if (nbnode == 13) {
279         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
280                                                  node[4], node[5], node[6], node[7],
281                                                  node[8], node[9], node[10],node[11],
282                                                  node[12],ID);
283         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
284                                                  node[4], node[5], node[6], node[7],
285                                                  node[8], node[9], node[10],node[11],
286                                                  node[12] );
287       }
288       else if (nbnode == 15) {
289         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
290                                                  node[4], node[5], node[6], node[7],
291                                                  node[8], node[9], node[10],node[11],
292                                                  node[12],node[13],node[14],ID);
293         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
294                                                  node[4], node[5], node[6], node[7],
295                                                  node[8], node[9], node[10],node[11],
296                                                  node[12],node[13],node[14] );
297       }
298       else if (nbnode == 20) {
299         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
300                                                  node[4], node[5], node[6], node[7],
301                                                  node[8], node[9], node[10],node[11],
302                                                  node[12],node[13],node[14],node[15],
303                                                  node[16],node[17],node[18],node[19],ID);
304         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
305                                                  node[4], node[5], node[6], node[7],
306                                                  node[8], node[9], node[10],node[11],
307                                                  node[12],node[13],node[14],node[15],
308                                                  node[16],node[17],node[18],node[19] );
309       }
310       else if (nbnode == 27) {
311         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
312                                                  node[4], node[5], node[6], node[7],
313                                                  node[8], node[9], node[10],node[11],
314                                                  node[12],node[13],node[14],node[15],
315                                                  node[16],node[17],node[18],node[19],
316                                                  node[20],node[21],node[22],node[23],
317                                                  node[24],node[25],node[26], ID);
318         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
319                                                  node[4], node[5], node[6], node[7],
320                                                  node[8], node[9], node[10],node[11],
321                                                  node[12],node[13],node[14],node[15],
322                                                  node[16],node[17],node[18],node[19],
323                                                  node[20],node[21],node[22],node[23],
324                                                  node[24],node[25],node[26] );
325       }
326     }
327     else if ( !features.myIsQuad )
328     {
329       if ( ID >= 1 ) e = mesh->AddPolyhedralVolumeWithID(node, features.myPolyhedQuantities, ID);
330       else           e = mesh->AddPolyhedralVolume      (node, features.myPolyhedQuantities    );
331     }
332     else
333     {
334       // if ( ID >= 1 ) e = mesh->AddQuadPolyhedralVolumeWithID(node, features.myPolyhedQuantities,ID);
335       // else           e = mesh->AddQuadPolyhedralVolume      (node, features.myPolyhedQuantities   );
336     }
337     break;
338
339   case SMDSAbs_Edge:
340     if ( nbnode == 2 ) {
341       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
342       else           e = mesh->AddEdge      (node[0], node[1] );
343     }
344     else if ( nbnode == 3 ) {
345       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
346       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
347     }
348     break;
349
350   case SMDSAbs_0DElement:
351     if ( nbnode == 1 ) {
352       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
353       else           e = mesh->Add0DElement      (node[0] );
354     }
355     break;
356
357   case SMDSAbs_Node:
358     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
359     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z()    );
360     break;
361
362   case SMDSAbs_Ball:
363     if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], features.myBallDiameter, ID);
364     else           e = mesh->AddBall      (node[0], features.myBallDiameter    );
365     break;
366
367   default:;
368   }
369   if ( e ) myLastCreatedElems.Append( e );
370   return e;
371 }
372
373 //=======================================================================
374 /*!
375  * \brief Add element
376  */
377 //=======================================================================
378
379 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
380                                                const ElemFeatures& features)
381 {
382   vector<const SMDS_MeshNode*> nodes;
383   nodes.reserve( nodeIDs.size() );
384   vector<int>::const_iterator id = nodeIDs.begin();
385   while ( id != nodeIDs.end() ) {
386     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
387       nodes.push_back( node );
388     else
389       return 0;
390   }
391   return AddElement( nodes, features );
392 }
393
394 //=======================================================================
395 //function : Remove
396 //purpose  : Remove a node or an element.
397 //           Modify a compute state of sub-meshes which become empty
398 //=======================================================================
399
400 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
401                               const bool         isNodes )
402 {
403   myLastCreatedElems.Clear();
404   myLastCreatedNodes.Clear();
405
406   SMESHDS_Mesh* aMesh = GetMeshDS();
407   set< SMESH_subMesh *> smmap;
408
409   int removed = 0;
410   list<int>::const_iterator it = theIDs.begin();
411   for ( ; it != theIDs.end(); it++ ) {
412     const SMDS_MeshElement * elem;
413     if ( isNodes )
414       elem = aMesh->FindNode( *it );
415     else
416       elem = aMesh->FindElement( *it );
417     if ( !elem )
418       continue;
419
420     // Notify VERTEX sub-meshes about modification
421     if ( isNodes ) {
422       const SMDS_MeshNode* node = cast2Node( elem );
423       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
424         if ( int aShapeID = node->getshapeId() )
425           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
426             smmap.insert( sm );
427     }
428     // Find sub-meshes to notify about modification
429     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
430     //     while ( nodeIt->more() ) {
431     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
432     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
433     //       if ( aPosition.get() ) {
434     //         if ( int aShapeID = aPosition->GetShapeId() ) {
435     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
436     //             smmap.insert( sm );
437     //         }
438     //       }
439     //     }
440
441     // Do remove
442     if ( isNodes )
443       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
444     else
445       aMesh->RemoveElement( elem );
446     removed++;
447   }
448
449   // Notify sub-meshes about modification
450   if ( !smmap.empty() ) {
451     set< SMESH_subMesh *>::iterator smIt;
452     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
453       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
454   }
455
456   //   // Check if the whole mesh becomes empty
457   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
458   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
459
460   return removed;
461 }
462
463 //================================================================================
464 /*!
465  * \brief Create 0D elements on all nodes of the given object except those
466  *        nodes on which a 0D element already exists.
467  *  \param elements - Elements on whose nodes to create 0D elements; if empty, 
468  *                    the all mesh is treated
469  *  \param all0DElems - returns all 0D elements found or created on nodes of \a elements
470  */
471 //================================================================================
472
473 void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements,
474                                                    TIDSortedElemSet&       all0DElems )
475 {
476   SMDS_ElemIteratorPtr elemIt;
477   vector< const SMDS_MeshElement* > allNodes;
478   if ( elements.empty() )
479   {
480     allNodes.reserve( GetMeshDS()->NbNodes() );
481     elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node );
482     while ( elemIt->more() )
483       allNodes.push_back( elemIt->next() );
484
485     elemIt = elemSetIterator( allNodes );
486   }
487   else
488   {
489     elemIt = elemSetIterator( elements );
490   }
491
492   while ( elemIt->more() )
493   {
494     const SMDS_MeshElement* e = elemIt->next();
495     SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
496     while ( nodeIt->more() )
497     {
498       const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
499       SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement );
500       if ( it0D->more() )
501         all0DElems.insert( it0D->next() );
502       else {
503         myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n ));
504         all0DElems.insert( myLastCreatedElems.Last() );
505       }
506     }
507   }
508 }
509
510 //=======================================================================
511 //function : FindShape
512 //purpose  : Return an index of the shape theElem is on
513 //           or zero if a shape not found
514 //=======================================================================
515
516 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
517 {
518   myLastCreatedElems.Clear();
519   myLastCreatedNodes.Clear();
520
521   SMESHDS_Mesh * aMesh = GetMeshDS();
522   if ( aMesh->ShapeToMesh().IsNull() )
523     return 0;
524
525   int aShapeID = theElem->getshapeId();
526   if ( aShapeID < 1 )
527     return 0;
528
529   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
530     if ( sm->Contains( theElem ))
531       return aShapeID;
532
533   if ( theElem->GetType() == SMDSAbs_Node ) {
534     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
535   }
536   else {
537     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
538   }
539
540   TopoDS_Shape aShape; // the shape a node of theElem is on
541   if ( theElem->GetType() != SMDSAbs_Node )
542   {
543     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
544     while ( nodeIt->more() ) {
545       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
546       if ((aShapeID = node->getshapeId()) > 0) {
547         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
548           if ( sm->Contains( theElem ))
549             return aShapeID;
550           if ( aShape.IsNull() )
551             aShape = aMesh->IndexToShape( aShapeID );
552         }
553       }
554     }
555   }
556
557   // None of nodes is on a proper shape,
558   // find the shape among ancestors of aShape on which a node is
559   if ( !aShape.IsNull() ) {
560     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
561     for ( ; ancIt.More(); ancIt.Next() ) {
562       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
563       if ( sm && sm->Contains( theElem ))
564         return aMesh->ShapeToIndex( ancIt.Value() );
565     }
566   }
567   else
568   {
569     SMESHDS_SubMeshIteratorPtr smIt = GetMeshDS()->SubMeshes();
570     while ( const SMESHDS_SubMesh* sm = smIt->next() )
571       if ( sm->Contains( theElem ))
572         return sm->GetID();
573   }
574
575   return 0;
576 }
577
578 //=======================================================================
579 //function : IsMedium
580 //purpose  :
581 //=======================================================================
582
583 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
584                                 const SMDSAbs_ElementType typeToCheck)
585 {
586   bool isMedium = false;
587   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
588   while (it->more() && !isMedium ) {
589     const SMDS_MeshElement* elem = it->next();
590     isMedium = elem->IsMediumNode(node);
591   }
592   return isMedium;
593 }
594
595 //=======================================================================
596 //function : shiftNodesQuadTria
597 //purpose  : Shift nodes in the array corresponded to quadratic triangle
598 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
599 //=======================================================================
600
601 static void shiftNodesQuadTria(vector< const SMDS_MeshNode* >& aNodes)
602 {
603   const SMDS_MeshNode* nd1 = aNodes[0];
604   aNodes[0] = aNodes[1];
605   aNodes[1] = aNodes[2];
606   aNodes[2] = nd1;
607   const SMDS_MeshNode* nd2 = aNodes[3];
608   aNodes[3] = aNodes[4];
609   aNodes[4] = aNodes[5];
610   aNodes[5] = nd2;
611 }
612
613 //=======================================================================
614 //function : nbEdgeConnectivity
615 //purpose  : return number of the edges connected with the theNode.
616 //           if theEdges has connections with the other type of the
617 //           elements, return -1
618 //=======================================================================
619
620 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
621 {
622   // SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
623   // int nb=0;
624   // while(elemIt->more()) {
625   //   elemIt->next();
626   //   nb++;
627   // }
628   // return nb;
629   return theNode->NbInverseElements();
630 }
631
632 //=======================================================================
633 //function : getNodesFromTwoTria
634 //purpose  : 
635 //=======================================================================
636
637 static bool getNodesFromTwoTria(const SMDS_MeshElement * theTria1,
638                                 const SMDS_MeshElement * theTria2,
639                                 vector< const SMDS_MeshNode*>& N1,
640                                 vector< const SMDS_MeshNode*>& N2)
641 {
642   N1.assign( theTria1->begin_nodes(), theTria1->end_nodes() );
643   if ( N1.size() < 6 ) return false;
644   N2.assign( theTria2->begin_nodes(), theTria2->end_nodes() );
645   if ( N2.size() < 6 ) return false;
646
647   int sames[3] = {-1,-1,-1};
648   int nbsames = 0;
649   int i, j;
650   for(i=0; i<3; i++) {
651     for(j=0; j<3; j++) {
652       if(N1[i]==N2[j]) {
653         sames[i] = j;
654         nbsames++;
655         break;
656       }
657     }
658   }
659   if(nbsames!=2) return false;
660   if(sames[0]>-1) {
661     shiftNodesQuadTria(N1);
662     if(sames[1]>-1) {
663       shiftNodesQuadTria(N1);
664     }
665   }
666   i = sames[0] + sames[1] + sames[2];
667   for(; i<2; i++) {
668     shiftNodesQuadTria(N2);
669   }
670   // now we receive following N1 and N2 (using numeration as in the image below)
671   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
672   // i.e. first nodes from both arrays form a new diagonal
673   return true;
674 }
675
676 //=======================================================================
677 //function : InverseDiag
678 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
679 //           but having other common link.
680 //           Return False if args are improper
681 //=======================================================================
682
683 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
684                                     const SMDS_MeshElement * theTria2 )
685 {
686   MESSAGE("InverseDiag");
687   myLastCreatedElems.Clear();
688   myLastCreatedNodes.Clear();
689
690   if (!theTria1 || !theTria2)
691     return false;
692
693   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
694   if (!F1) return false;
695   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
696   if (!F2) return false;
697   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
698       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
699
700     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
701     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
702     //    |/ |                                         | \|
703     //  B +--+ 2                                     B +--+ 2
704
705     // put nodes in array and find out indices of the same ones
706     const SMDS_MeshNode* aNodes [6];
707     int sameInd [] = { -1, -1, -1, -1, -1, -1 };
708     int i = 0;
709     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
710     while ( it->more() ) {
711       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
712
713       if ( i > 2 ) // theTria2
714         // find same node of theTria1
715         for ( int j = 0; j < 3; j++ )
716           if ( aNodes[ i ] == aNodes[ j ]) {
717             sameInd[ j ] = i;
718             sameInd[ i ] = j;
719             break;
720           }
721       // next
722       i++;
723       if ( i == 3 ) {
724         if ( it->more() )
725           return false; // theTria1 is not a triangle
726         it = theTria2->nodesIterator();
727       }
728       if ( i == 6 && it->more() )
729         return false; // theTria2 is not a triangle
730     }
731
732     // find indices of 1,2 and of A,B in theTria1
733     int iA = -1, iB = 0, i1 = 0, i2 = 0;
734     for ( i = 0; i < 6; i++ ) {
735       if ( sameInd [ i ] == -1 ) {
736         if ( i < 3 ) i1 = i;
737         else         i2 = i;
738       }
739       else if (i < 3) {
740         if ( iA >= 0) iB = i;
741         else          iA = i;
742       }
743     }
744     // nodes 1 and 2 should not be the same
745     if ( aNodes[ i1 ] == aNodes[ i2 ] )
746       return false;
747
748     // theTria1: A->2
749     aNodes[ iA ] = aNodes[ i2 ];
750     // theTria2: B->1
751     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
752
753     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
754     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
755
756     return true;
757
758   } // end if(F1 && F2)
759
760   // check case of quadratic faces
761   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle &&
762       theTria1->GetEntityType() != SMDSEntity_BiQuad_Triangle)
763     return false;
764   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle&&
765       theTria2->GetEntityType() != SMDSEntity_BiQuad_Triangle)
766     return false;
767
768   //       5
769   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
770   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
771   //    |   / |
772   //  7 +  +  + 6
773   //    | /9  |
774   //    |/    |
775   //  4 +--+--+ 3
776   //       8
777
778   vector< const SMDS_MeshNode* > N1;
779   vector< const SMDS_MeshNode* > N2;
780   if(!getNodesFromTwoTria(theTria1,theTria2,N1,N2))
781     return false;
782   // now we receive following N1 and N2 (using numeration as above image)
783   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
784   // i.e. first nodes from both arrays determ new diagonal
785
786   vector< const SMDS_MeshNode*> N1new( N1.size() );
787   vector< const SMDS_MeshNode*> N2new( N2.size() );
788   N1new.back() = N1.back(); // central node of biquadratic
789   N2new.back() = N2.back();
790   N1new[0] = N1[0];  N2new[0] = N1[0];
791   N1new[1] = N2[0];  N2new[1] = N1[1];
792   N1new[2] = N2[1];  N2new[2] = N2[0];
793   N1new[3] = N1[4];  N2new[3] = N1[3];
794   N1new[4] = N2[3];  N2new[4] = N2[5];
795   N1new[5] = N1[5];  N2new[5] = N1[4];
796   // change nodes in faces
797   GetMeshDS()->ChangeElementNodes( theTria1, &N1new[0], N1new.size() );
798   GetMeshDS()->ChangeElementNodes( theTria2, &N2new[0], N2new.size() );
799
800   // move the central node of biquadratic triangle
801   SMESH_MesherHelper helper( *GetMesh() );
802   for ( int is2nd = 0; is2nd < 2; ++is2nd )
803   {
804     const SMDS_MeshElement*         tria = is2nd ? theTria2 : theTria1;
805     vector< const SMDS_MeshNode*>& nodes = is2nd ? N2new : N1new;
806     if ( nodes.size() < 7 )
807       continue;
808     helper.SetSubShape( tria->getshapeId() );
809     const TopoDS_Face& F = TopoDS::Face( helper.GetSubShape() );
810     gp_Pnt xyz;
811     if ( F.IsNull() )
812     {
813       xyz = ( SMESH_TNodeXYZ( nodes[3] ) +
814               SMESH_TNodeXYZ( nodes[4] ) +
815               SMESH_TNodeXYZ( nodes[5] )) / 3.;
816     }
817     else
818     {
819       bool checkUV;
820       gp_XY uv = ( helper.GetNodeUV( F, nodes[3], nodes[2], &checkUV ) +
821                    helper.GetNodeUV( F, nodes[4], nodes[0], &checkUV ) +
822                    helper.GetNodeUV( F, nodes[5], nodes[1], &checkUV )) / 3.;
823       TopLoc_Location loc;
824       Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc);
825       xyz = S->Value( uv.X(), uv.Y() );
826       xyz.Transform( loc );
827       if ( nodes[6]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE &&  // set UV
828            nodes[6]->getshapeId() > 0 )
829         GetMeshDS()->SetNodeOnFace( nodes[6], nodes[6]->getshapeId(), uv.X(), uv.Y() );
830     }
831     GetMeshDS()->MoveNode( nodes[6], xyz.X(), xyz.Y(), xyz.Z() );
832   }
833   return true;
834 }
835
836 //=======================================================================
837 //function : findTriangles
838 //purpose  : find triangles sharing theNode1-theNode2 link
839 //=======================================================================
840
841 static bool findTriangles(const SMDS_MeshNode *    theNode1,
842                           const SMDS_MeshNode *    theNode2,
843                           const SMDS_MeshElement*& theTria1,
844                           const SMDS_MeshElement*& theTria2)
845 {
846   if ( !theNode1 || !theNode2 ) return false;
847
848   theTria1 = theTria2 = 0;
849
850   set< const SMDS_MeshElement* > emap;
851   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
852   while (it->more()) {
853     const SMDS_MeshElement* elem = it->next();
854     if ( elem->NbCornerNodes() == 3 )
855       emap.insert( elem );
856   }
857   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
858   while (it->more()) {
859     const SMDS_MeshElement* elem = it->next();
860     if ( emap.count( elem )) {
861       if ( !theTria1 )
862       {
863         theTria1 = elem;
864       }
865       else  
866       {
867         theTria2 = elem;
868         // theTria1 must be element with minimum ID
869         if ( theTria2->GetID() < theTria1->GetID() )
870           std::swap( theTria2, theTria1 );
871         return true;
872       }
873     }
874   }
875   return false;
876 }
877
878 //=======================================================================
879 //function : InverseDiag
880 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
881 //           with ones built on the same 4 nodes but having other common link.
882 //           Return false if proper faces not found
883 //=======================================================================
884
885 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
886                                     const SMDS_MeshNode * theNode2)
887 {
888   myLastCreatedElems.Clear();
889   myLastCreatedNodes.Clear();
890
891   MESSAGE( "::InverseDiag()" );
892
893   const SMDS_MeshElement *tr1, *tr2;
894   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
895     return false;
896
897   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
898   if (!F1) return false;
899   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
900   if (!F2) return false;
901   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
902       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
903
904     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
905     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
906     //    |/ |                                    | \|
907     //  B +--+ 2                                B +--+ 2
908
909     // put nodes in array
910     // and find indices of 1,2 and of A in tr1 and of B in tr2
911     int i, iA1 = 0, i1 = 0;
912     const SMDS_MeshNode* aNodes1 [3];
913     SMDS_ElemIteratorPtr it;
914     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
915       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
916       if ( aNodes1[ i ] == theNode1 )
917         iA1 = i; // node A in tr1
918       else if ( aNodes1[ i ] != theNode2 )
919         i1 = i;  // node 1
920     }
921     int iB2 = 0, i2 = 0;
922     const SMDS_MeshNode* aNodes2 [3];
923     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
924       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
925       if ( aNodes2[ i ] == theNode2 )
926         iB2 = i; // node B in tr2
927       else if ( aNodes2[ i ] != theNode1 )
928         i2 = i;  // node 2
929     }
930
931     // nodes 1 and 2 should not be the same
932     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
933       return false;
934
935     // tr1: A->2
936     aNodes1[ iA1 ] = aNodes2[ i2 ];
937     // tr2: B->1
938     aNodes2[ iB2 ] = aNodes1[ i1 ];
939
940     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
941     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
942
943     return true;
944   }
945
946   // check case of quadratic faces
947   return InverseDiag(tr1,tr2);
948 }
949
950 //=======================================================================
951 //function : getQuadrangleNodes
952 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
953 //           fusion of triangles tr1 and tr2 having shared link on
954 //           theNode1 and theNode2
955 //=======================================================================
956
957 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
958                         const SMDS_MeshNode *    theNode1,
959                         const SMDS_MeshNode *    theNode2,
960                         const SMDS_MeshElement * tr1,
961                         const SMDS_MeshElement * tr2 )
962 {
963   if( tr1->NbNodes() != tr2->NbNodes() )
964     return false;
965   // find the 4-th node to insert into tr1
966   const SMDS_MeshNode* n4 = 0;
967   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
968   int i=0;
969   while ( !n4 && i<3 ) {
970     const SMDS_MeshNode * n = cast2Node( it->next() );
971     i++;
972     bool isDiag = ( n == theNode1 || n == theNode2 );
973     if ( !isDiag )
974       n4 = n;
975   }
976   // Make an array of nodes to be in a quadrangle
977   int iNode = 0, iFirstDiag = -1;
978   it = tr1->nodesIterator();
979   i=0;
980   while ( i<3 ) {
981     const SMDS_MeshNode * n = cast2Node( it->next() );
982     i++;
983     bool isDiag = ( n == theNode1 || n == theNode2 );
984     if ( isDiag ) {
985       if ( iFirstDiag < 0 )
986         iFirstDiag = iNode;
987       else if ( iNode - iFirstDiag == 1 )
988         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
989     }
990     else if ( n == n4 ) {
991       return false; // tr1 and tr2 should not have all the same nodes
992     }
993     theQuadNodes[ iNode++ ] = n;
994   }
995   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
996     theQuadNodes[ iNode ] = n4;
997
998   return true;
999 }
1000
1001 //=======================================================================
1002 //function : DeleteDiag
1003 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
1004 //           with a quadrangle built on the same 4 nodes.
1005 //           Return false if proper faces not found
1006 //=======================================================================
1007
1008 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
1009                                    const SMDS_MeshNode * theNode2)
1010 {
1011   myLastCreatedElems.Clear();
1012   myLastCreatedNodes.Clear();
1013
1014   MESSAGE( "::DeleteDiag()" );
1015
1016   const SMDS_MeshElement *tr1, *tr2;
1017   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
1018     return false;
1019
1020   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
1021   if (!F1) return false;
1022   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
1023   if (!F2) return false;
1024   SMESHDS_Mesh * aMesh = GetMeshDS();
1025
1026   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
1027       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
1028
1029     const SMDS_MeshNode* aNodes [ 4 ];
1030     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
1031       return false;
1032
1033     const SMDS_MeshElement* newElem = 0;
1034     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
1035     myLastCreatedElems.Append(newElem);
1036     AddToSameGroups( newElem, tr1, aMesh );
1037     int aShapeId = tr1->getshapeId();
1038     if ( aShapeId )
1039       {
1040         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1041       }
1042     aMesh->RemoveElement( tr1 );
1043     aMesh->RemoveElement( tr2 );
1044
1045     return true;
1046   }
1047
1048   // check case of quadratic faces
1049   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
1050     return false;
1051   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
1052     return false;
1053
1054   //       5
1055   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
1056   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
1057   //    |   / |
1058   //  7 +  +  + 6
1059   //    | /9  |
1060   //    |/    |
1061   //  4 +--+--+ 3
1062   //       8
1063
1064   vector< const SMDS_MeshNode* > N1;
1065   vector< const SMDS_MeshNode* > N2;
1066   if(!getNodesFromTwoTria(tr1,tr2,N1,N2))
1067     return false;
1068   // now we receive following N1 and N2 (using numeration as above image)
1069   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
1070   // i.e. first nodes from both arrays determ new diagonal
1071
1072   const SMDS_MeshNode* aNodes[8];
1073   aNodes[0] = N1[0];
1074   aNodes[1] = N1[1];
1075   aNodes[2] = N2[0];
1076   aNodes[3] = N2[1];
1077   aNodes[4] = N1[3];
1078   aNodes[5] = N2[5];
1079   aNodes[6] = N2[3];
1080   aNodes[7] = N1[5];
1081
1082   const SMDS_MeshElement* newElem = 0;
1083   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
1084                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
1085   myLastCreatedElems.Append(newElem);
1086   AddToSameGroups( newElem, tr1, aMesh );
1087   int aShapeId = tr1->getshapeId();
1088   if ( aShapeId )
1089     {
1090       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1091     }
1092   aMesh->RemoveElement( tr1 );
1093   aMesh->RemoveElement( tr2 );
1094
1095   // remove middle node (9)
1096   GetMeshDS()->RemoveNode( N1[4] );
1097
1098   return true;
1099 }
1100
1101 //=======================================================================
1102 //function : Reorient
1103 //purpose  : Reverse theElement orientation
1104 //=======================================================================
1105
1106 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
1107 {
1108   MESSAGE("Reorient");
1109   myLastCreatedElems.Clear();
1110   myLastCreatedNodes.Clear();
1111
1112   if (!theElem)
1113     return false;
1114   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
1115   if ( !it || !it->more() )
1116     return false;
1117
1118   const SMDSAbs_ElementType type = theElem->GetType();
1119   if ( type < SMDSAbs_Edge || type > SMDSAbs_Volume )
1120     return false;
1121
1122   const SMDSAbs_EntityType geomType = theElem->GetEntityType();
1123   if ( geomType == SMDSEntity_Polyhedra ) // polyhedron
1124   {
1125     const SMDS_VtkVolume* aPolyedre =
1126       dynamic_cast<const SMDS_VtkVolume*>( theElem );
1127     if (!aPolyedre) {
1128       MESSAGE("Warning: bad volumic element");
1129       return false;
1130     }
1131     const int nbFaces = aPolyedre->NbFaces();
1132     vector<const SMDS_MeshNode *> poly_nodes;
1133     vector<int> quantities (nbFaces);
1134
1135     // reverse each face of the polyedre
1136     for (int iface = 1; iface <= nbFaces; iface++) {
1137       int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1138       quantities[iface - 1] = nbFaceNodes;
1139
1140       for (inode = nbFaceNodes; inode >= 1; inode--) {
1141         const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1142         poly_nodes.push_back(curNode);
1143       }
1144     }
1145     return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1146   }
1147   else // other elements
1148   {
1149     vector<const SMDS_MeshNode*> nodes( theElem->begin_nodes(), theElem->end_nodes() );
1150     const std::vector<int>& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType, nodes.size() );
1151     if ( interlace.empty() )
1152     {
1153       std::reverse( nodes.begin(), nodes.end() ); // obsolete, just in case
1154     }
1155     else
1156     {
1157       SMDS_MeshCell::applyInterlace( interlace, nodes );
1158     }
1159     return GetMeshDS()->ChangeElementNodes( theElem, &nodes[0], nodes.size() );
1160   }
1161   return false;
1162 }
1163
1164 //================================================================================
1165 /*!
1166  * \brief Reorient faces.
1167  * \param theFaces - the faces to reorient. If empty the whole mesh is meant
1168  * \param theDirection - desired direction of normal of \a theFace
1169  * \param theFace - one of \a theFaces that sould be oriented according to
1170  *        \a theDirection and whose orientation defines orientation of other faces
1171  * \return number of reoriented faces.
1172  */
1173 //================================================================================
1174
1175 int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
1176                                   const gp_Dir&            theDirection,
1177                                   const SMDS_MeshElement * theFace)
1178 {
1179   int nbReori = 0;
1180   if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori;
1181
1182   if ( theFaces.empty() )
1183   {
1184     SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true);
1185     while ( fIt->more() )
1186       theFaces.insert( theFaces.end(), fIt->next() );
1187   }
1188
1189   // orient theFace according to theDirection
1190   gp_XYZ normal;
1191   SMESH_MeshAlgos::FaceNormal( theFace, normal, /*normalized=*/false );
1192   if ( normal * theDirection.XYZ() < 0 )
1193     nbReori += Reorient( theFace );
1194
1195   // Orient other faces
1196
1197   set< const SMDS_MeshElement* > startFaces, visitedFaces;
1198   TIDSortedElemSet avoidSet;
1199   set< SMESH_TLink > checkedLinks;
1200   pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
1201
1202   if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
1203     theFaces.erase( theFace );
1204   startFaces.insert( theFace );
1205
1206   int nodeInd1, nodeInd2;
1207   const SMDS_MeshElement*           otherFace;
1208   vector< const SMDS_MeshElement* > facesNearLink;
1209   vector< std::pair< int, int > >   nodeIndsOfFace;
1210
1211   set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
1212   while ( !startFaces.empty() )
1213   {
1214     startFace = startFaces.begin();
1215     theFace = *startFace;
1216     startFaces.erase( startFace );
1217     if ( !visitedFaces.insert( theFace ).second )
1218       continue;
1219
1220     avoidSet.clear();
1221     avoidSet.insert(theFace);
1222
1223     NLink link( theFace->GetNode( 0 ), (SMDS_MeshNode *) 0 );
1224
1225     const int nbNodes = theFace->NbCornerNodes();
1226     for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
1227     {
1228       link.second = theFace->GetNode(( i+1 ) % nbNodes );
1229       linkIt_isNew = checkedLinks.insert( link );
1230       if ( !linkIt_isNew.second )
1231       {
1232         // link has already been checked and won't be encountered more
1233         // if the group (theFaces) is manifold
1234         //checkedLinks.erase( linkIt_isNew.first );
1235       }
1236       else
1237       {
1238         facesNearLink.clear();
1239         nodeIndsOfFace.clear();
1240         while (( otherFace = SMESH_MeshAlgos::FindFaceInSet( link.first, link.second,
1241                                                              theFaces, avoidSet,
1242                                                              &nodeInd1, &nodeInd2 )))
1243           if ( otherFace != theFace)
1244           {
1245             facesNearLink.push_back( otherFace );
1246             nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 ));
1247             avoidSet.insert( otherFace );
1248           }
1249         if ( facesNearLink.size() > 1 )
1250         {
1251           // NON-MANIFOLD mesh shell !
1252           // select a face most co-directed with theFace,
1253           // other faces won't be visited this time
1254           gp_XYZ NF, NOF;
1255           SMESH_MeshAlgos::FaceNormal( theFace, NF, /*normalized=*/false );
1256           double proj, maxProj = -1;
1257           for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
1258             SMESH_MeshAlgos::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
1259             if (( proj = Abs( NF * NOF )) > maxProj ) {
1260               maxProj = proj;
1261               otherFace = facesNearLink[i];
1262               nodeInd1  = nodeIndsOfFace[i].first;
1263               nodeInd2  = nodeIndsOfFace[i].second;
1264             }
1265           }
1266           // not to visit rejected faces
1267           for ( size_t i = 0; i < facesNearLink.size(); ++i )
1268             if ( facesNearLink[i] != otherFace && theFaces.size() > 1 )
1269               visitedFaces.insert( facesNearLink[i] );
1270         }
1271         else if ( facesNearLink.size() == 1 )
1272         {
1273           otherFace = facesNearLink[0];
1274           nodeInd1  = nodeIndsOfFace.back().first;
1275           nodeInd2  = nodeIndsOfFace.back().second;
1276         }
1277         if ( otherFace && otherFace != theFace)
1278         {
1279           // link must be reverse in otherFace if orientation ot otherFace
1280           // is same as that of theFace
1281           if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
1282           {
1283             nbReori += Reorient( otherFace );
1284           }
1285           startFaces.insert( otherFace );
1286         }
1287       }
1288       std::swap( link.first, link.second ); // reverse the link
1289     }
1290   }
1291   return nbReori;
1292 }
1293
1294 //================================================================================
1295 /*!
1296  * \brief Reorient faces basing on orientation of adjacent volumes.
1297  * \param theFaces - faces to reorient. If empty, all mesh faces are treated.
1298  * \param theVolumes - reference volumes.
1299  * \param theOutsideNormal - to orient faces to have their normal
1300  *        pointing either \a outside or \a inside the adjacent volumes.
1301  * \return number of reoriented faces.
1302  */
1303 //================================================================================
1304
1305 int SMESH_MeshEditor::Reorient2DBy3D (TIDSortedElemSet & theFaces,
1306                                       TIDSortedElemSet & theVolumes,
1307                                       const bool         theOutsideNormal)
1308 {
1309   int nbReori = 0;
1310
1311   SMDS_ElemIteratorPtr faceIt;
1312   if ( theFaces.empty() )
1313     faceIt = GetMeshDS()->elementsIterator( SMDSAbs_Face );
1314   else
1315     faceIt = elemSetIterator( theFaces );
1316
1317   vector< const SMDS_MeshNode* > faceNodes;
1318   TIDSortedElemSet checkedVolumes;
1319   set< const SMDS_MeshNode* > faceNodesSet;
1320   SMDS_VolumeTool volumeTool;
1321
1322   while ( faceIt->more() ) // loop on given faces
1323   {
1324     const SMDS_MeshElement* face = faceIt->next();
1325     if ( face->GetType() != SMDSAbs_Face )
1326       continue;
1327
1328     const int nbCornersNodes = face->NbCornerNodes();
1329     faceNodes.assign( face->begin_nodes(), face->end_nodes() );
1330
1331     checkedVolumes.clear();
1332     SMDS_ElemIteratorPtr vIt = faceNodes[ 0 ]->GetInverseElementIterator( SMDSAbs_Volume );
1333     while ( vIt->more() )
1334     {
1335       const SMDS_MeshElement* volume = vIt->next();
1336
1337       if ( !checkedVolumes.insert( volume ).second )
1338         continue;
1339       if ( !theVolumes.empty() && !theVolumes.count( volume ))
1340         continue;
1341
1342       // is volume adjacent?
1343       bool allNodesCommon = true;
1344       for ( int iN = 1; iN < nbCornersNodes && allNodesCommon; ++iN )
1345         allNodesCommon = ( volume->GetNodeIndex( faceNodes[ iN ]) > -1 );
1346       if ( !allNodesCommon )
1347         continue;
1348
1349       // get nodes of a corresponding volume facet
1350       faceNodesSet.clear();
1351       faceNodesSet.insert( faceNodes.begin(), faceNodes.end() );
1352       volumeTool.Set( volume );
1353       int facetID = volumeTool.GetFaceIndex( faceNodesSet );
1354       if ( facetID < 0 ) continue;
1355       volumeTool.SetExternalNormal();
1356       const SMDS_MeshNode** facetNodes = volumeTool.GetFaceNodes( facetID );
1357
1358       // compare order of faceNodes and facetNodes
1359       const int iQ = 1 + ( nbCornersNodes < faceNodes.size() );
1360       int iNN[2];
1361       for ( int i = 0; i < 2; ++i )
1362       {
1363         const SMDS_MeshNode* n = facetNodes[ i*iQ ];
1364         for ( int iN = 0; iN < nbCornersNodes; ++iN )
1365           if ( faceNodes[ iN ] == n )
1366           {
1367             iNN[ i ] = iN;
1368             break;
1369           }
1370       }
1371       bool isOutside = Abs( iNN[0]-iNN[1] ) == 1 ? iNN[0] < iNN[1] : iNN[0] > iNN[1];
1372       if ( isOutside != theOutsideNormal )
1373         nbReori += Reorient( face );
1374     }
1375   }  // loop on given faces
1376
1377   return nbReori;
1378 }
1379
1380 //=======================================================================
1381 //function : getBadRate
1382 //purpose  :
1383 //=======================================================================
1384
1385 static double getBadRate (const SMDS_MeshElement*               theElem,
1386                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1387 {
1388   SMESH::Controls::TSequenceOfXYZ P;
1389   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1390     return 1e100;
1391   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1392   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1393 }
1394
1395 //=======================================================================
1396 //function : QuadToTri
1397 //purpose  : Cut quadrangles into triangles.
1398 //           theCrit is used to select a diagonal to cut
1399 //=======================================================================
1400
1401 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1402                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1403 {
1404   myLastCreatedElems.Clear();
1405   myLastCreatedNodes.Clear();
1406
1407   if ( !theCrit.get() )
1408     return false;
1409
1410   SMESHDS_Mesh * aMesh = GetMeshDS();
1411
1412   Handle(Geom_Surface) surface;
1413   SMESH_MesherHelper   helper( *GetMesh() );
1414
1415   TIDSortedElemSet::iterator itElem;
1416   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
1417   {
1418     const SMDS_MeshElement* elem = *itElem;
1419     if ( !elem || elem->GetType() != SMDSAbs_Face )
1420       continue;
1421     if ( elem->NbCornerNodes() != 4 )
1422       continue;
1423
1424     // retrieve element nodes
1425     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1426
1427     // compare two sets of possible triangles
1428     double aBadRate1, aBadRate2; // to what extent a set is bad
1429     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1430     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1431     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1432
1433     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1434     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1435     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1436
1437     const int aShapeId = FindShape( elem );
1438     const SMDS_MeshElement* newElem1 = 0;
1439     const SMDS_MeshElement* newElem2 = 0;
1440
1441     if ( !elem->IsQuadratic() ) // split liner quadrangle
1442     {
1443       // for MaxElementLength2D functor we return minimum diagonal for splitting,
1444       // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1445       if ( aBadRate1 <= aBadRate2 ) {
1446         // tr1 + tr2 is better
1447         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1448         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1449       }
1450       else {
1451         // tr3 + tr4 is better
1452         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1453         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1454       }
1455     }
1456     else // split quadratic quadrangle
1457     {
1458       helper.SetIsQuadratic( true );
1459       helper.SetIsBiQuadratic( aNodes.size() == 9 );
1460
1461       helper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem ));
1462       if ( aNodes.size() == 9 )
1463       {
1464         helper.SetIsBiQuadratic( true );
1465         if ( aBadRate1 <= aBadRate2 )
1466           helper.AddTLinkNode( aNodes[0], aNodes[2], aNodes[8] );
1467         else
1468           helper.AddTLinkNode( aNodes[1], aNodes[3], aNodes[8] );
1469       }
1470       // create a new element
1471       if ( aBadRate1 <= aBadRate2 ) {
1472         newElem1 = helper.AddFace( aNodes[2], aNodes[3], aNodes[0] );
1473         newElem2 = helper.AddFace( aNodes[2], aNodes[0], aNodes[1] );
1474       }
1475       else {
1476         newElem1 = helper.AddFace( aNodes[3], aNodes[0], aNodes[1] );
1477         newElem2 = helper.AddFace( aNodes[3], aNodes[1], aNodes[2] );
1478       }
1479     } // quadratic case
1480
1481     // care of a new element
1482
1483     myLastCreatedElems.Append(newElem1);
1484     myLastCreatedElems.Append(newElem2);
1485     AddToSameGroups( newElem1, elem, aMesh );
1486     AddToSameGroups( newElem2, elem, aMesh );
1487
1488     // put a new triangle on the same shape
1489     if ( aShapeId )
1490       aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1491     aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1492
1493     aMesh->RemoveElement( elem );
1494   }
1495   return true;
1496 }
1497
1498 //=======================================================================
1499 /*!
1500  * \brief Split each of given quadrangles into 4 triangles.
1501  * \param theElems - The faces to be splitted. If empty all faces are split.
1502  */
1503 //=======================================================================
1504
1505 void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
1506 {
1507   myLastCreatedElems.Clear();
1508   myLastCreatedNodes.Clear();
1509
1510   SMESH_MesherHelper helper( *GetMesh() );
1511   helper.SetElementsOnShape( true );
1512
1513   SMDS_ElemIteratorPtr faceIt;
1514   if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face);
1515   else                    faceIt = elemSetIterator( theElems );
1516
1517   bool   checkUV;
1518   gp_XY  uv [9]; uv[8] = gp_XY(0,0);
1519   gp_XYZ xyz[9];
1520   vector< const SMDS_MeshNode* > nodes;
1521   SMESHDS_SubMesh*               subMeshDS;
1522   TopoDS_Face                    F;
1523   Handle(Geom_Surface)           surface;
1524   TopLoc_Location                loc;
1525
1526   while ( faceIt->more() )
1527   {
1528     const SMDS_MeshElement* quad = faceIt->next();
1529     if ( !quad || quad->NbCornerNodes() != 4 )
1530       continue;
1531
1532     // get a surface the quad is on
1533
1534     if ( quad->getshapeId() < 1 )
1535     {
1536       F.Nullify();
1537       helper.SetSubShape( 0 );
1538       subMeshDS = 0;
1539     }
1540     else if ( quad->getshapeId() != helper.GetSubShapeID() )
1541     {
1542       helper.SetSubShape( quad->getshapeId() );
1543       if ( !helper.GetSubShape().IsNull() &&
1544            helper.GetSubShape().ShapeType() == TopAbs_FACE )
1545       {
1546         F = TopoDS::Face( helper.GetSubShape() );
1547         surface = BRep_Tool::Surface( F, loc );
1548         subMeshDS = GetMeshDS()->MeshElements( quad->getshapeId() );
1549       }
1550       else
1551       {
1552         helper.SetSubShape( 0 );
1553         subMeshDS = 0;
1554       }
1555     }
1556
1557     // create a central node
1558
1559     const SMDS_MeshNode* nCentral;
1560     nodes.assign( quad->begin_nodes(), quad->end_nodes() );
1561
1562     if ( nodes.size() == 9 )
1563     {
1564       nCentral = nodes.back();
1565     }
1566     else
1567     {
1568       size_t iN = 0;
1569       if ( F.IsNull() )
1570       {
1571         for ( ; iN < nodes.size(); ++iN )
1572           xyz[ iN ] = SMESH_TNodeXYZ( nodes[ iN ] );
1573
1574         for ( ; iN < 8; ++iN ) // mid-side points of a linear qudrangle
1575           xyz[ iN ] = 0.5 * ( xyz[ iN - 4 ] + xyz[( iN - 3 )%4 ] );
1576
1577         xyz[ 8 ] = helper.calcTFI( 0.5, 0.5,
1578                                    xyz[0], xyz[1], xyz[2], xyz[3],
1579                                    xyz[4], xyz[5], xyz[6], xyz[7] );
1580       }
1581       else
1582       {
1583         for ( ; iN < nodes.size(); ++iN )
1584           uv[ iN ] = helper.GetNodeUV( F, nodes[iN], nodes[(iN+2)%4], &checkUV );
1585
1586         for ( ; iN < 8; ++iN ) // UV of mid-side points of a linear qudrangle
1587           uv[ iN ] = helper.GetMiddleUV( surface, uv[ iN - 4 ], uv[( iN - 3 )%4 ] );
1588
1589         uv[ 8 ] = helper.calcTFI( 0.5, 0.5,
1590                                   uv[0], uv[1], uv[2], uv[3],
1591                                   uv[4], uv[5], uv[6], uv[7] );
1592
1593         gp_Pnt p = surface->Value( uv[8].X(), uv[8].Y() ).Transformed( loc );
1594         xyz[ 8 ] = p.XYZ();
1595       }
1596
1597       nCentral = helper.AddNode( xyz[8].X(), xyz[8].Y(), xyz[8].Z(), /*id=*/0,
1598                                  uv[8].X(), uv[8].Y() );
1599       myLastCreatedNodes.Append( nCentral );
1600     }
1601
1602     // create 4 triangles
1603
1604     GetMeshDS()->RemoveFreeElement( quad, subMeshDS, /*fromGroups=*/false );
1605     
1606     helper.SetIsQuadratic  ( nodes.size() > 4 );
1607     helper.SetIsBiQuadratic( nodes.size() == 9 );
1608     if ( helper.GetIsQuadratic() )
1609       helper.AddTLinks( static_cast< const SMDS_MeshFace*>( quad ));
1610
1611     for ( int i = 0; i < 4; ++i )
1612     {
1613       SMDS_MeshElement* tria = helper.AddFace( nodes[ i ],
1614                                                nodes[(i+1)%4],
1615                                                nCentral );
1616       ReplaceElemInGroups( tria, quad, GetMeshDS() );
1617       myLastCreatedElems.Append( tria );
1618     }
1619   }
1620 }
1621
1622 //=======================================================================
1623 //function : BestSplit
1624 //purpose  : Find better diagonal for cutting.
1625 //=======================================================================
1626
1627 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1628                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1629 {
1630   myLastCreatedElems.Clear();
1631   myLastCreatedNodes.Clear();
1632
1633   if (!theCrit.get())
1634     return -1;
1635
1636   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1637     return -1;
1638
1639   if( theQuad->NbNodes()==4 ||
1640       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1641
1642     // retrieve element nodes
1643     const SMDS_MeshNode* aNodes [4];
1644     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1645     int i = 0;
1646     //while (itN->more())
1647     while (i<4) {
1648       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1649     }
1650     // compare two sets of possible triangles
1651     double aBadRate1, aBadRate2; // to what extent a set is bad
1652     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1653     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1654     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1655
1656     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1657     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1658     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1659     // for MaxElementLength2D functor we return minimum diagonal for splitting,
1660     // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1661     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1662       return 1; // diagonal 1-3
1663
1664     return 2; // diagonal 2-4
1665   }
1666   return -1;
1667 }
1668
1669 namespace
1670 {
1671   // Methods of splitting volumes into tetra
1672
1673   const int theHexTo5_1[5*4+1] =
1674     {
1675       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1676     };
1677   const int theHexTo5_2[5*4+1] =
1678     {
1679       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1680     };
1681   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1682
1683   const int theHexTo6_1[6*4+1] =
1684     {
1685       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
1686     };
1687   const int theHexTo6_2[6*4+1] =
1688     {
1689       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
1690     };
1691   const int theHexTo6_3[6*4+1] =
1692     {
1693       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
1694     };
1695   const int theHexTo6_4[6*4+1] =
1696     {
1697       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
1698     };
1699   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1700
1701   const int thePyraTo2_1[2*4+1] =
1702     {
1703       0, 1, 2, 4,    0, 2, 3, 4,   -1
1704     };
1705   const int thePyraTo2_2[2*4+1] =
1706     {
1707       1, 2, 3, 4,    1, 3, 0, 4,   -1
1708     };
1709   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1710
1711   const int thePentaTo3_1[3*4+1] =
1712     {
1713       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1714     };
1715   const int thePentaTo3_2[3*4+1] =
1716     {
1717       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1718     };
1719   const int thePentaTo3_3[3*4+1] =
1720     {
1721       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1722     };
1723   const int thePentaTo3_4[3*4+1] =
1724     {
1725       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1726     };
1727   const int thePentaTo3_5[3*4+1] =
1728     {
1729       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1730     };
1731   const int thePentaTo3_6[3*4+1] =
1732     {
1733       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1734     };
1735   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1736                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1737
1738   // Methods of splitting hexahedron into prisms
1739
1740   const int theHexTo4Prisms_BT[6*4+1] = // bottom-top
1741     {
1742       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
1743     };
1744   const int theHexTo4Prisms_LR[6*4+1] = // left-right
1745     {
1746       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
1747     };
1748   const int theHexTo4Prisms_FB[6*4+1] = // front-back
1749     {
1750       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
1751     };
1752
1753   const int theHexTo2Prisms_BT_1[6*2+1] =
1754     {
1755       0, 1, 3, 4, 5, 7,    1, 2, 3, 5, 6, 7,   -1
1756     };
1757   const int theHexTo2Prisms_BT_2[6*2+1] =
1758     {
1759       0, 1, 2, 4, 5, 6,    0, 2, 3, 4, 6, 7,   -1
1760     };
1761   const int* theHexTo2Prisms_BT[2] = { theHexTo2Prisms_BT_1, theHexTo2Prisms_BT_2 };
1762
1763   const int theHexTo2Prisms_LR_1[6*2+1] =
1764     {
1765       1, 0, 4, 2, 3, 7,    1, 4, 5, 2, 7, 6,   -1
1766     };
1767   const int theHexTo2Prisms_LR_2[6*2+1] =
1768     {
1769       1, 0, 4, 2, 3, 7,    1, 4, 5, 2, 7, 6,   -1
1770     };
1771   const int* theHexTo2Prisms_LR[2] = { theHexTo2Prisms_LR_1, theHexTo2Prisms_LR_2 };
1772
1773   const int theHexTo2Prisms_FB_1[6*2+1] =
1774     {
1775       0, 3, 4, 1, 2, 5,    3, 7, 4, 2, 6, 5,   -1
1776     };
1777   const int theHexTo2Prisms_FB_2[6*2+1] =
1778     {
1779       0, 3, 7, 1, 2, 7,    0, 7, 4, 1, 6, 5,   -1
1780     };
1781   const int* theHexTo2Prisms_FB[2] = { theHexTo2Prisms_FB_1, theHexTo2Prisms_FB_2 };
1782
1783
1784   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1785   {
1786     int _n1, _n2, _n3;
1787     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1788     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1789     bool hasAdjacentVol( const SMDS_MeshElement*    elem,
1790                          const SMDSAbs_GeometryType geom = SMDSGeom_TETRA) const;
1791   };
1792   struct TSplitMethod
1793   {
1794     int        _nbSplits;
1795     int        _nbCorners;
1796     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1797     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1798     bool       _ownConn;      //!< to delete _connectivity in destructor
1799     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1800
1801     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1802       : _nbSplits(nbTet), _nbCorners(4), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1803     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1804     bool hasFacet( const TTriangleFacet& facet ) const
1805     {
1806       if ( _nbCorners == 4 )
1807       {
1808         const int* tetConn = _connectivity;
1809         for ( ; tetConn[0] >= 0; tetConn += 4 )
1810           if (( facet.contains( tetConn[0] ) +
1811                 facet.contains( tetConn[1] ) +
1812                 facet.contains( tetConn[2] ) +
1813                 facet.contains( tetConn[3] )) == 3 )
1814             return true;
1815       }
1816       else // prism, _nbCorners == 6
1817       {
1818         const int* prismConn = _connectivity;
1819         for ( ; prismConn[0] >= 0; prismConn += 6 )
1820         {
1821           if (( facet.contains( prismConn[0] ) &&
1822                 facet.contains( prismConn[1] ) &&
1823                 facet.contains( prismConn[2] ))
1824               ||
1825               ( facet.contains( prismConn[3] ) &&
1826                 facet.contains( prismConn[4] ) &&
1827                 facet.contains( prismConn[5] )))
1828             return true;
1829         }
1830       }
1831       return false;
1832     }
1833   };
1834
1835   //=======================================================================
1836   /*!
1837    * \brief return TSplitMethod for the given element to split into tetrahedra
1838    */
1839   //=======================================================================
1840
1841   TSplitMethod getTetraSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1842   {
1843     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1844
1845     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1846     // an edge and a face barycenter; tertaherdons are based on triangles and
1847     // a volume barycenter
1848     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1849
1850     // Find out how adjacent volumes are split
1851
1852     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1853     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1854     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1855     {
1856       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1857       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1858       if ( nbNodes < 4 ) continue;
1859
1860       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1861       const int* nInd = vol.GetFaceNodesIndices( iF );
1862       if ( nbNodes == 4 )
1863       {
1864         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1865         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1866         if      ( t012.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t012 );
1867         else if ( t123.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t123 );
1868       }
1869       else
1870       {
1871         int iCom = 0; // common node of triangle faces to split into
1872         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1873         {
1874           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1875                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1876                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1877           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1878                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1879                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1880           if ( t012.hasAdjacentVol( vol.Element() ) && t023.hasAdjacentVol( vol.Element() ))
1881           {
1882             triaSplits.push_back( t012 );
1883             triaSplits.push_back( t023 );
1884             break;
1885           }
1886         }
1887       }
1888       if ( !triaSplits.empty() )
1889         hasAdjacentSplits = true;
1890     }
1891
1892     // Among variants of split method select one compliant with adjacent volumes
1893
1894     TSplitMethod method;
1895     if ( !vol.Element()->IsPoly() && !is24TetMode )
1896     {
1897       int nbVariants = 2, nbTet = 0;
1898       const int** connVariants = 0;
1899       switch ( vol.Element()->GetEntityType() )
1900       {
1901       case SMDSEntity_Hexa:
1902       case SMDSEntity_Quad_Hexa:
1903       case SMDSEntity_TriQuad_Hexa:
1904         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1905           connVariants = theHexTo5, nbTet = 5;
1906         else
1907           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1908         break;
1909       case SMDSEntity_Pyramid:
1910       case SMDSEntity_Quad_Pyramid:
1911         connVariants = thePyraTo2;  nbTet = 2;
1912         break;
1913       case SMDSEntity_Penta:
1914       case SMDSEntity_Quad_Penta:
1915         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1916         break;
1917       default:
1918         nbVariants = 0;
1919       }
1920       for ( int variant = 0; variant < nbVariants && method._nbSplits == 0; ++variant )
1921       {
1922         // check method compliancy with adjacent tetras,
1923         // all found splits must be among facets of tetras described by this method
1924         method = TSplitMethod( nbTet, connVariants[variant] );
1925         if ( hasAdjacentSplits && method._nbSplits > 0 )
1926         {
1927           bool facetCreated = true;
1928           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1929           {
1930             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1931             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1932               facetCreated = method.hasFacet( *facet );
1933           }
1934           if ( !facetCreated )
1935             method = TSplitMethod(0); // incompatible method
1936         }
1937       }
1938     }
1939     if ( method._nbSplits < 1 )
1940     {
1941       // No standard method is applicable, use a generic solution:
1942       // each facet of a volume is split into triangles and
1943       // each of triangles and a volume barycenter form a tetrahedron.
1944
1945       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1946
1947       int* connectivity = new int[ maxTetConnSize + 1 ];
1948       method._connectivity = connectivity;
1949       method._ownConn = true;
1950       method._baryNode = !isHex27; // to create central node or not
1951
1952       int connSize = 0;
1953       int baryCenInd = vol.NbNodes() - int( isHex27 );
1954       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1955       {
1956         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1957         const int*   nInd = vol.GetFaceNodesIndices( iF );
1958         // find common node of triangle facets of tetra to create
1959         int iCommon = 0; // index in linear numeration
1960         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1961         if ( !triaSplits.empty() )
1962         {
1963           // by found facets
1964           const TTriangleFacet* facet = &triaSplits.front();
1965           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1966             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1967                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1968               break;
1969         }
1970         else if ( nbNodes > 3 && !is24TetMode )
1971         {
1972           // find the best method of splitting into triangles by aspect ratio
1973           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1974           map< double, int > badness2iCommon;
1975           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1976           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1977           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1978           {
1979             double badness = 0;
1980             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1981             {
1982               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1983                                       nodes[ iQ*((iLast-1)%nbNodes)],
1984                                       nodes[ iQ*((iLast  )%nbNodes)]);
1985               badness += getBadRate( &tria, aspectRatio );
1986             }
1987             badness2iCommon.insert( make_pair( badness, iCommon ));
1988           }
1989           // use iCommon with lowest badness
1990           iCommon = badness2iCommon.begin()->second;
1991         }
1992         if ( iCommon >= nbNodes )
1993           iCommon = 0; // something wrong
1994
1995         // fill connectivity of tetrahedra based on a current face
1996         int nbTet = nbNodes - 2;
1997         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1998         {
1999           int faceBaryCenInd;
2000           if ( isHex27 )
2001           {
2002             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
2003             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
2004           }
2005           else
2006           {
2007             method._faceBaryNode[ iF ] = 0;
2008             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
2009           }
2010           nbTet = nbNodes;
2011           for ( int i = 0; i < nbTet; ++i )
2012           {
2013             int i1 = i, i2 = (i+1) % nbNodes;
2014             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
2015             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
2016             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
2017             connectivity[ connSize++ ] = faceBaryCenInd;
2018             connectivity[ connSize++ ] = baryCenInd;
2019           }
2020         }
2021         else
2022         {
2023           for ( int i = 0; i < nbTet; ++i )
2024           {
2025             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
2026             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
2027             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
2028             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
2029             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
2030             connectivity[ connSize++ ] = baryCenInd;
2031           }
2032         }
2033         method._nbSplits += nbTet;
2034
2035       } // loop on volume faces
2036
2037       connectivity[ connSize++ ] = -1;
2038
2039     } // end of generic solution
2040
2041     return method;
2042   }
2043   //=======================================================================
2044   /*!
2045    * \brief return TSplitMethod to split haxhedron into prisms
2046    */
2047   //=======================================================================
2048
2049   TSplitMethod getPrismSplitMethod( SMDS_VolumeTool& vol,
2050                                     const int        methodFlags,
2051                                     const int        facetToSplit)
2052   {
2053     // order of facets in HEX according to SMDS_VolumeTool::Hexa_F :
2054     // B, T, L, B, R, F
2055     const int iF = ( facetToSplit < 2 ) ? 0 : 1 + ( facetToSplit-2 ) % 2; // [0,1,2]
2056
2057     if ( methodFlags == SMESH_MeshEditor::HEXA_TO_4_PRISMS )
2058     {
2059       static TSplitMethod to4methods[4]; // order BT, LR, FB
2060       if ( to4methods[iF]._nbSplits == 0 )
2061       {
2062         switch ( iF ) {
2063         case 0:
2064           to4methods[iF]._connectivity = theHexTo4Prisms_BT;
2065           to4methods[iF]._faceBaryNode[ 0 ] = 0;
2066           to4methods[iF]._faceBaryNode[ 1 ] = 0;
2067           break;
2068         case 1:
2069           to4methods[iF]._connectivity = theHexTo4Prisms_LR;
2070           to4methods[iF]._faceBaryNode[ 2 ] = 0;
2071           to4methods[iF]._faceBaryNode[ 4 ] = 0;
2072           break;
2073         case 2:
2074           to4methods[iF]._connectivity = theHexTo4Prisms_FB;
2075           to4methods[iF]._faceBaryNode[ 3 ] = 0;
2076           to4methods[iF]._faceBaryNode[ 5 ] = 0;
2077           break;
2078         default: return to4methods[3];
2079         }
2080         to4methods[iF]._nbSplits  = 4;
2081         to4methods[iF]._nbCorners = 6;
2082       }
2083       return to4methods[iF];
2084     }
2085     // else if ( methodFlags == HEXA_TO_2_PRISMS )
2086
2087     TSplitMethod method;
2088
2089     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
2090
2091     const int nbVariants = 2, nbSplits = 2;
2092     const int** connVariants = 0;
2093     switch ( iF ) {
2094     case 0: connVariants = theHexTo2Prisms_BT; break;
2095     case 1: connVariants = theHexTo2Prisms_LR; break;
2096     case 2: connVariants = theHexTo2Prisms_FB; break;
2097     default: return method;
2098     }
2099
2100     // look for prisms adjacent via facetToSplit and an opposite one
2101     for ( int is2nd = 0; is2nd < 2; ++is2nd )
2102     {
2103       int iFacet = is2nd ? vol.GetOppFaceIndexOfHex( facetToSplit ) : facetToSplit;
2104       int nbNodes = vol.NbFaceNodes( iFacet ) / iQ;
2105       if ( nbNodes != 4 ) return method;
2106
2107       const int* nInd = vol.GetFaceNodesIndices( iFacet );
2108       TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
2109       TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
2110       TTriangleFacet* t;
2111       if      ( t012.hasAdjacentVol( vol.Element(), SMDSGeom_PENTA ))
2112         t = &t012;
2113       else if ( t123.hasAdjacentVol( vol.Element(), SMDSGeom_PENTA ))
2114         t = &t123;
2115       else
2116         continue;
2117
2118       // there are adjacent prism
2119       for ( int variant = 0; variant < nbVariants; ++variant )
2120       {
2121         // check method compliancy with adjacent prisms,
2122         // the found prism facets must be among facets of prisms described by current method
2123         method._nbSplits     = nbSplits;
2124         method._nbCorners    = 6;
2125         method._connectivity = connVariants[ variant ];
2126         if ( method.hasFacet( *t ))
2127           return method;
2128       }
2129     }
2130
2131     // No adjacent prisms. Select a variant with a best aspect ratio.
2132
2133     double badness[2] = { 0, 0 };
2134     static SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
2135     const SMDS_MeshNode** nodes = vol.GetNodes();
2136     for ( int variant = 0; variant < nbVariants; ++variant )
2137       for ( int is2nd = 0; is2nd < 2; ++is2nd )
2138       {
2139         int iFacet = is2nd ? vol.GetOppFaceIndexOfHex( facetToSplit ) : facetToSplit;
2140         const int*             nInd = vol.GetFaceNodesIndices( iFacet );
2141
2142         method._connectivity = connVariants[ variant ];
2143         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
2144         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
2145         TTriangleFacet* t = ( method.hasFacet( t012 )) ? & t012 : & t123;
2146
2147         SMDS_FaceOfNodes tria ( nodes[ t->_n1 ],
2148                                 nodes[ t->_n2 ],
2149                                 nodes[ t->_n3 ] );
2150         badness[ variant ] += getBadRate( &tria, aspectRatio );
2151       }
2152     const int iBetter = ( badness[1] < badness[0] && badness[0]-badness[1] > 0.1 * badness[0] );
2153
2154     method._nbSplits     = nbSplits;
2155     method._nbCorners    = 6;
2156     method._connectivity = connVariants[ iBetter ];
2157
2158     return method;
2159   }
2160
2161   //================================================================================
2162   /*!
2163    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
2164    */
2165   //================================================================================
2166
2167   bool TTriangleFacet::hasAdjacentVol( const SMDS_MeshElement*    elem,
2168                                        const SMDSAbs_GeometryType geom ) const
2169   {
2170     // find the tetrahedron including the three nodes of facet
2171     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
2172     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
2173     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
2174     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
2175     while ( volIt1->more() )
2176     {
2177       const SMDS_MeshElement* v = volIt1->next();
2178       if ( v->GetGeomType() != geom )
2179         continue;
2180       const int lastCornerInd = v->NbCornerNodes() - 1;
2181       if ( v->IsQuadratic() && v->GetNodeIndex( n1 ) > lastCornerInd )
2182         continue; // medium node not allowed
2183       const int ind2 = v->GetNodeIndex( n2 );
2184       if ( ind2 < 0 || lastCornerInd < ind2 )
2185         continue;
2186       const int ind3 = v->GetNodeIndex( n3 );
2187       if ( ind3 < 0 || lastCornerInd < ind3 )
2188         continue;
2189       return true;
2190     }
2191     return false;
2192   }
2193
2194   //=======================================================================
2195   /*!
2196    * \brief A key of a face of volume
2197    */
2198   //=======================================================================
2199
2200   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
2201   {
2202     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
2203     {
2204       TIDSortedNodeSet sortedNodes;
2205       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
2206       int nbNodes = vol.NbFaceNodes( iF );
2207       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
2208       for ( int i = 0; i < nbNodes; i += iQ )
2209         sortedNodes.insert( fNodes[i] );
2210       TIDSortedNodeSet::iterator n = sortedNodes.begin();
2211       first.first   = (*(n++))->GetID();
2212       first.second  = (*(n++))->GetID();
2213       second.first  = (*(n++))->GetID();
2214       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
2215     }
2216   };
2217 } // namespace
2218
2219 //=======================================================================
2220 //function : SplitVolumes
2221 //purpose  : Split volume elements into tetrahedra or prisms.
2222 //           If facet ID < 0, element is split into tetrahedra,
2223 //           else a hexahedron is split into prisms so that the given facet is
2224 //           split into triangles
2225 //=======================================================================
2226
2227 void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems,
2228                                      const int            theMethodFlags)
2229 {
2230   SMDS_VolumeTool    volTool;
2231   SMESH_MesherHelper helper( *GetMesh()), fHelper(*GetMesh());
2232   fHelper.ToFixNodeParameters( true );
2233
2234   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
2235   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
2236
2237   SMESH_SequenceOfElemPtr newNodes, newElems;
2238
2239   // map face of volume to it's baricenrtic node
2240   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
2241   double bc[3];
2242   vector<const SMDS_MeshElement* > splitVols;
2243
2244   TFacetOfElem::const_iterator elem2facet = theElems.begin();
2245   for ( ; elem2facet != theElems.end(); ++elem2facet )
2246   {
2247     const SMDS_MeshElement* elem = elem2facet->first;
2248     const int       facetToSplit = elem2facet->second;
2249     if ( elem->GetType() != SMDSAbs_Volume )
2250       continue;
2251     const SMDSAbs_EntityType geomType = elem->GetEntityType();
2252     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
2253       continue;
2254
2255     if ( !volTool.Set( elem, /*ignoreCentralNodes=*/false )) continue; // strange...
2256
2257     TSplitMethod splitMethod = ( facetToSplit < 0  ?
2258                                  getTetraSplitMethod( volTool, theMethodFlags ) :
2259                                  getPrismSplitMethod( volTool, theMethodFlags, facetToSplit ));
2260     if ( splitMethod._nbSplits < 1 ) continue;
2261
2262     // find submesh to add new tetras to
2263     if ( !subMesh || !subMesh->Contains( elem ))
2264     {
2265       int shapeID = FindShape( elem );
2266       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
2267       subMesh = GetMeshDS()->MeshElements( shapeID );
2268     }
2269     int iQ;
2270     if ( elem->IsQuadratic() )
2271     {
2272       iQ = 2;
2273       // add quadratic links to the helper
2274       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
2275       {
2276         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
2277         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
2278         for ( int iN = 0; iN < nbN; iN += iQ )
2279           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
2280       }
2281       helper.SetIsQuadratic( true );
2282     }
2283     else
2284     {
2285       iQ = 1;
2286       helper.SetIsQuadratic( false );
2287     }
2288     vector<const SMDS_MeshNode*> nodes( volTool.GetNodes(),
2289                                         volTool.GetNodes() + elem->NbNodes() );
2290     helper.SetElementsOnShape( true );
2291     if ( splitMethod._baryNode )
2292     {
2293       // make a node at barycenter
2294       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
2295       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
2296       nodes.push_back( gcNode );
2297       newNodes.Append( gcNode );
2298     }
2299     if ( !splitMethod._faceBaryNode.empty() )
2300     {
2301       // make or find baricentric nodes of faces
2302       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
2303       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
2304       {
2305         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
2306           volFace2BaryNode.insert
2307           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
2308         if ( !f_n->second )
2309         {
2310           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
2311           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
2312         }
2313         nodes.push_back( iF_n->second = f_n->second );
2314       }
2315     }
2316
2317     // make new volumes
2318     splitVols.resize( splitMethod._nbSplits ); // splits of a volume
2319     const int* volConn = splitMethod._connectivity;
2320     if ( splitMethod._nbCorners == 4 ) // tetra
2321       for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners )
2322         newElems.Append( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ],
2323                                                             nodes[ volConn[1] ],
2324                                                             nodes[ volConn[2] ],
2325                                                             nodes[ volConn[3] ]));
2326     else // prisms
2327       for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners )
2328         newElems.Append( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ],
2329                                                             nodes[ volConn[1] ],
2330                                                             nodes[ volConn[2] ],
2331                                                             nodes[ volConn[3] ],
2332                                                             nodes[ volConn[4] ],
2333                                                             nodes[ volConn[5] ]));
2334
2335     ReplaceElemInGroups( elem, splitVols, GetMeshDS() );
2336
2337     // Split faces on sides of the split volume
2338
2339     const SMDS_MeshNode** volNodes = volTool.GetNodes();
2340     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
2341     {
2342       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
2343       if ( nbNodes < 4 ) continue;
2344
2345       // find an existing face
2346       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
2347                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
2348       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
2349                                                                        /*noMedium=*/false))
2350       {
2351         // make triangles
2352         helper.SetElementsOnShape( false );
2353         vector< const SMDS_MeshElement* > triangles;
2354
2355         // find submesh to add new triangles in
2356         if ( !fSubMesh || !fSubMesh->Contains( face ))
2357         {
2358           int shapeID = FindShape( face );
2359           fSubMesh = GetMeshDS()->MeshElements( shapeID );
2360         }
2361         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
2362         if ( iF_n != splitMethod._faceBaryNode.end() )
2363         {
2364           const SMDS_MeshNode *baryNode = iF_n->second;
2365           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
2366           {
2367             const SMDS_MeshNode* n1 = fNodes[iN];
2368             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
2369             const SMDS_MeshNode *n3 = baryNode;
2370             if ( !volTool.IsFaceExternal( iF ))
2371               swap( n2, n3 );
2372             triangles.push_back( helper.AddFace( n1,n2,n3 ));
2373           }
2374           if ( fSubMesh ) // update position of the bary node on geometry
2375           {
2376             if ( subMesh )
2377               subMesh->RemoveNode( baryNode, false );
2378             GetMeshDS()->SetNodeOnFace( baryNode, fSubMesh->GetID() );
2379             const TopoDS_Shape& s = GetMeshDS()->IndexToShape( fSubMesh->GetID() );
2380             if ( !s.IsNull() && s.ShapeType() == TopAbs_FACE )
2381             {
2382               fHelper.SetSubShape( s );
2383               gp_XY uv( 1e100, 1e100 );
2384               double distXYZ[4];
2385               if ( !fHelper.CheckNodeUV( TopoDS::Face( s ), baryNode,
2386                                         uv, /*tol=*/1e-7, /*force=*/true, distXYZ ) &&
2387                    uv.X() < 1e100 )
2388               {
2389                 // node is too far from the surface
2390                 GetMeshDS()->MoveNode( baryNode, distXYZ[1], distXYZ[2], distXYZ[3] );
2391                 const_cast<SMDS_MeshNode*>( baryNode )->SetPosition
2392                   ( SMDS_PositionPtr( new SMDS_FacePosition( uv.X(), uv.Y() )));
2393               }
2394             }
2395           }
2396         }
2397         else
2398         {
2399           // among possible triangles create ones discribed by split method
2400           const int* nInd = volTool.GetFaceNodesIndices( iF );
2401           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
2402           int iCom = 0; // common node of triangle faces to split into
2403           list< TTriangleFacet > facets;
2404           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
2405           {
2406             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
2407                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
2408                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
2409             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
2410                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
2411                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
2412             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
2413             {
2414               facets.push_back( t012 );
2415               facets.push_back( t023 );
2416               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
2417                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
2418                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
2419                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
2420               break;
2421             }
2422           }
2423           list< TTriangleFacet >::iterator facet = facets.begin();
2424           if ( facet == facets.end() )
2425             break;
2426           for ( ; facet != facets.end(); ++facet )
2427           {
2428             if ( !volTool.IsFaceExternal( iF ))
2429               swap( facet->_n2, facet->_n3 );
2430             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
2431                                                  volNodes[ facet->_n2 ],
2432                                                  volNodes[ facet->_n3 ]));
2433           }
2434         }
2435         for ( int i = 0; i < triangles.size(); ++i )
2436         {
2437           if ( !triangles[i] ) continue;
2438           if ( fSubMesh )
2439             fSubMesh->AddElement( triangles[i]);
2440           newElems.Append( triangles[i] );
2441         }
2442         ReplaceElemInGroups( face, triangles, GetMeshDS() );
2443         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
2444
2445       } // while a face based on facet nodes exists
2446     } // loop on volume faces to split them into triangles
2447
2448     GetMeshDS()->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false );
2449
2450     if ( geomType == SMDSEntity_TriQuad_Hexa )
2451     {
2452       // remove medium nodes that could become free
2453       for ( int i = 20; i < volTool.NbNodes(); ++i )
2454         if ( volNodes[i]->NbInverseElements() == 0 )
2455           GetMeshDS()->RemoveNode( volNodes[i] );
2456     }
2457   } // loop on volumes to split
2458   
2459   myLastCreatedNodes = newNodes;
2460   myLastCreatedElems = newElems;
2461 }
2462
2463 //=======================================================================
2464 //function : GetHexaFacetsToSplit
2465 //purpose  : For hexahedra that will be split into prisms, finds facets to
2466 //           split into triangles. Only hexahedra adjacent to the one closest
2467 //           to theFacetNormal.Location() are returned.
2468 //param [in,out] theHexas - the hexahedra
2469 //param [in]     theFacetNormal - facet normal
2470 //param [out]    theFacets - the hexahedra and found facet IDs
2471 //=======================================================================
2472
2473 void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas,
2474                                              const gp_Ax1&     theFacetNormal,
2475                                              TFacetOfElem &    theFacets)
2476 {
2477   #define THIS_METHOD "SMESH_MeshEditor::GetHexaFacetsToSplit(): "
2478
2479   // Find a hexa closest to the location of theFacetNormal
2480
2481   const SMDS_MeshElement* startHex;
2482   {
2483     // get SMDS_ElemIteratorPtr on theHexas
2484     typedef const SMDS_MeshElement*                                      TValue;
2485     typedef TIDSortedElemSet::iterator                                   TSetIterator;
2486     typedef SMDS::SimpleAccessor<TValue,TSetIterator>                    TAccesor;
2487     typedef SMDS_MeshElement::GeomFilter                                 TFilter;
2488     typedef SMDS_SetIterator < TValue, TSetIterator, TAccesor, TFilter > TElemSetIter;
2489     SMDS_ElemIteratorPtr elemIt = SMDS_ElemIteratorPtr
2490       ( new TElemSetIter( theHexas.begin(),
2491                           theHexas.end(),
2492                           SMDS_MeshElement::GeomFilter( SMDSGeom_HEXA )));
2493
2494     SMESH_ElementSearcher* searcher =
2495       SMESH_MeshAlgos::GetElementSearcher( *myMesh->GetMeshDS(), elemIt );
2496
2497     startHex = searcher->FindClosestTo( theFacetNormal.Location(), SMDSAbs_Volume );
2498
2499     delete searcher;
2500
2501     if ( !startHex )
2502       throw SALOME_Exception( THIS_METHOD "startHex not found");
2503   }
2504
2505   // Select a facet of startHex by theFacetNormal
2506
2507   SMDS_VolumeTool vTool( startHex );
2508   double norm[3], dot, maxDot = 0;
2509   int facetID = -1;
2510   for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
2511     if ( vTool.GetFaceNormal( iF, norm[0], norm[1], norm[2] ))
2512     {
2513       dot = Abs( theFacetNormal.Direction().Dot( gp_Dir( norm[0], norm[1], norm[2] )));
2514       if ( dot > maxDot )
2515       {
2516         facetID = iF;
2517         maxDot = dot;
2518       }
2519     }
2520   if ( facetID < 0 )
2521     throw SALOME_Exception( THIS_METHOD "facet of startHex not found");
2522
2523   // Fill theFacets starting from facetID of startHex
2524
2525   // facets used for seach of volumes adjacent to already treated ones
2526   typedef pair< TFacetOfElem::iterator, int > TElemFacets;
2527   typedef map< TVolumeFaceKey, TElemFacets  > TFacetMap;
2528   TFacetMap facetsToCheck;
2529
2530   set<const SMDS_MeshNode*> facetNodes;
2531   const SMDS_MeshElement*   curHex;
2532
2533   const bool allHex = ( theHexas.size() == myMesh->NbHexas() );
2534
2535   while ( startHex )
2536   {
2537     // move in two directions from startHex via facetID
2538     for ( int is2nd = 0; is2nd < 2; ++is2nd )
2539     {
2540       curHex       = startHex;
2541       int curFacet = facetID;
2542       if ( is2nd ) // do not treat startHex twice
2543       {
2544         vTool.Set( curHex );
2545         if ( vTool.IsFreeFace( curFacet, &curHex ))
2546         {
2547           curHex = 0;
2548         }
2549         else
2550         {
2551           vTool.GetFaceNodes( curFacet, facetNodes );
2552           vTool.Set( curHex );
2553           curFacet = vTool.GetFaceIndex( facetNodes );
2554         }
2555       }
2556       while ( curHex )
2557       {
2558         // store a facet to split
2559         if ( curHex->GetGeomType() != SMDSGeom_HEXA )
2560         {
2561           theFacets.insert( make_pair( curHex, -1 ));
2562           break;
2563         }
2564         if ( !allHex && !theHexas.count( curHex ))
2565           break;
2566
2567         pair< TFacetOfElem::iterator, bool > facetIt2isNew =
2568           theFacets.insert( make_pair( curHex, curFacet ));
2569         if ( !facetIt2isNew.second )
2570           break;
2571
2572         // remember not-to-split facets in facetsToCheck
2573         int oppFacet = vTool.GetOppFaceIndexOfHex( curFacet );
2574         for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
2575         {
2576           if ( iF == curFacet && iF == oppFacet )
2577             continue;
2578           TVolumeFaceKey facetKey ( vTool, iF );
2579           TElemFacets    elemFacet( facetIt2isNew.first, iF );
2580           pair< TFacetMap::iterator, bool > it2isnew =
2581             facetsToCheck.insert( make_pair( facetKey, elemFacet ));
2582           if ( !it2isnew.second )
2583             facetsToCheck.erase( it2isnew.first ); // adjacent hex already checked
2584         }
2585         // pass to a volume adjacent via oppFacet
2586         if ( vTool.IsFreeFace( oppFacet, &curHex ))
2587         {
2588           curHex = 0;
2589         }
2590         else
2591         {
2592           // get a new curFacet
2593           vTool.GetFaceNodes( oppFacet, facetNodes );
2594           vTool.Set( curHex );
2595           curFacet = vTool.GetFaceIndex( facetNodes, /*hint=*/curFacet );
2596         }
2597       }
2598     } // move in two directions from startHex via facetID
2599
2600     // Find a new startHex by facetsToCheck
2601
2602     startHex = 0;
2603     facetID  = -1;
2604     TFacetMap::iterator fIt = facetsToCheck.begin();
2605     while ( !startHex && fIt != facetsToCheck.end() )
2606     {
2607       const TElemFacets&  elemFacets = fIt->second;
2608       const SMDS_MeshElement*    hex = elemFacets.first->first;
2609       int                 splitFacet = elemFacets.first->second;
2610       int               lateralFacet = elemFacets.second;
2611       facetsToCheck.erase( fIt );
2612       fIt = facetsToCheck.begin();
2613
2614       vTool.Set( hex );
2615       if ( vTool.IsFreeFace( lateralFacet, &curHex ) || 
2616            curHex->GetGeomType() != SMDSGeom_HEXA )
2617         continue;
2618       if ( !allHex && !theHexas.count( curHex ))
2619         continue;
2620
2621       startHex = curHex;
2622
2623       // find a facet of startHex to split
2624
2625       set<const SMDS_MeshNode*> lateralNodes;
2626       vTool.GetFaceNodes( lateralFacet, lateralNodes );
2627       vTool.GetFaceNodes( splitFacet,   facetNodes );
2628       int oppLateralFacet = vTool.GetOppFaceIndexOfHex( lateralFacet );
2629       vTool.Set( startHex );
2630       lateralFacet = vTool.GetFaceIndex( lateralNodes, oppLateralFacet );
2631
2632       // look for a facet of startHex having common nodes with facetNodes
2633       // but not lateralFacet
2634       for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
2635       {
2636         if ( iF == lateralFacet )
2637           continue;
2638         int nbCommonNodes = 0;
2639         const SMDS_MeshNode** nn = vTool.GetFaceNodes( iF );
2640         for ( int iN = 0, nbN = vTool.NbFaceNodes( iF ); iN < nbN; ++iN )
2641           nbCommonNodes += facetNodes.count( nn[ iN ]);
2642
2643         if ( nbCommonNodes >= 2 )
2644         {
2645           facetID = iF;
2646           break;
2647         }
2648       }
2649       if ( facetID < 0 )
2650         throw SALOME_Exception( THIS_METHOD "facet of a new startHex not found");
2651     }
2652   } //   while ( startHex )
2653
2654   return;
2655 }
2656
2657 namespace
2658 {
2659   //================================================================================
2660   /*!
2661    * \brief Selects nodes of several elements according to a given interlace
2662    *  \param [in] srcNodes - nodes to select from
2663    *  \param [out] tgtNodesVec - array of nodes of several elements to fill in
2664    *  \param [in] interlace - indices of nodes for all elements
2665    *  \param [in] nbElems - nb of elements
2666    *  \param [in] nbNodes - nb of nodes in each element
2667    *  \param [in] mesh - the mesh
2668    *  \param [out] elemQueue - a list to push elements found by the selected nodes
2669    *  \param [in] type - type of elements to look for
2670    */
2671   //================================================================================
2672
2673   void selectNodes( const vector< const SMDS_MeshNode* >& srcNodes,
2674                     vector< const SMDS_MeshNode* >*       tgtNodesVec,
2675                     const int*                            interlace,
2676                     const int                             nbElems,
2677                     const int                             nbNodes,
2678                     SMESHDS_Mesh*                         mesh = 0,
2679                     list< const SMDS_MeshElement* >*      elemQueue=0,
2680                     SMDSAbs_ElementType                   type=SMDSAbs_All)
2681   {
2682     for ( int iE = 0; iE < nbElems; ++iE )
2683     {
2684       vector< const SMDS_MeshNode* >& elemNodes = tgtNodesVec[iE];
2685       const int*                         select = & interlace[iE*nbNodes];
2686       elemNodes.resize( nbNodes );
2687       for ( int iN = 0; iN < nbNodes; ++iN )
2688         elemNodes[iN] = srcNodes[ select[ iN ]];
2689     }
2690     const SMDS_MeshElement* e;
2691     if ( elemQueue )
2692       for ( int iE = 0; iE < nbElems; ++iE )
2693         if (( e = mesh->FindElement( tgtNodesVec[iE], type, /*noMedium=*/false)))
2694           elemQueue->push_back( e );
2695   }
2696 }
2697
2698 //=======================================================================
2699 /*
2700  * Split bi-quadratic elements into linear ones without creation of additional nodes
2701  *   - bi-quadratic triangle will be split into 3 linear quadrangles;
2702  *   - bi-quadratic quadrangle will be split into 4 linear quadrangles;
2703  *   - tri-quadratic hexahedron will be split into 8 linear hexahedra;
2704  *   Quadratic elements of lower dimension  adjacent to the split bi-quadratic element
2705  *   will be split in order to keep the mesh conformal.
2706  *  \param elems - elements to split
2707  */
2708 //=======================================================================
2709
2710 void SMESH_MeshEditor::SplitBiQuadraticIntoLinear(TIDSortedElemSet& theElems)
2711 {
2712   vector< const SMDS_MeshNode* > elemNodes(27), subNodes[12], splitNodes[8];
2713   vector<const SMDS_MeshElement* > splitElems;
2714   list< const SMDS_MeshElement* > elemQueue;
2715   list< const SMDS_MeshElement* >::iterator elemIt;
2716
2717   SMESHDS_Mesh * mesh = GetMeshDS();
2718   ElemFeatures *elemType, hexaType(SMDSAbs_Volume), quadType(SMDSAbs_Face), segType(SMDSAbs_Edge);
2719   int nbElems, nbNodes;
2720
2721   TIDSortedElemSet::iterator elemSetIt = theElems.begin();
2722   for ( ; elemSetIt != theElems.end(); ++elemSetIt )
2723   {
2724     elemQueue.clear();
2725     elemQueue.push_back( *elemSetIt );
2726     for ( elemIt = elemQueue.begin(); elemIt != elemQueue.end(); ++elemIt )
2727     {
2728       const SMDS_MeshElement* elem = *elemIt;
2729       switch( elem->GetEntityType() )
2730       {
2731       case SMDSEntity_TriQuad_Hexa: // HEX27
2732       {
2733         elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
2734         nbElems  = nbNodes = 8;
2735         elemType = & hexaType;
2736
2737         // get nodes for new elements
2738         static int vInd[8][8] = {{ 0,8,20,11,   16,21,26,24 },
2739                                  { 1,9,20,8,    17,22,26,21 },
2740                                  { 2,10,20,9,   18,23,26,22 },
2741                                  { 3,11,20,10,  19,24,26,23 },
2742                                  { 16,21,26,24, 4,12,25,15  },
2743                                  { 17,22,26,21, 5,13,25,12  },
2744                                  { 18,23,26,22, 6,14,25,13  },
2745                                  { 19,24,26,23, 7,15,25,14  }};
2746         selectNodes( elemNodes, & splitNodes[0], &vInd[0][0], nbElems, nbNodes );
2747
2748         // add boundary faces to elemQueue
2749         static int fInd[6][9] = {{ 0,1,2,3, 8,9,10,11,   20 },
2750                                  { 4,5,6,7, 12,13,14,15, 25 },
2751                                  { 0,1,5,4, 8,17,12,16,  21 },
2752                                  { 1,2,6,5, 9,18,13,17,  22 },
2753                                  { 2,3,7,6, 10,19,14,18, 23 },
2754                                  { 3,0,4,7, 11,16,15,19, 24 }};
2755         selectNodes( elemNodes, & subNodes[0], &fInd[0][0], 6,9, mesh, &elemQueue, SMDSAbs_Face );
2756
2757         // add boundary segments to elemQueue
2758         static int eInd[12][3] = {{ 0,1,8 }, { 1,2,9 }, { 2,3,10 }, { 3,0,11 },
2759                                   { 4,5,12}, { 5,6,13}, { 6,7,14 }, { 7,4,15 },
2760                                   { 0,4,16}, { 1,5,17}, { 2,6,18 }, { 3,7,19 }};
2761         selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 12,3, mesh, &elemQueue, SMDSAbs_Edge );
2762         break;
2763       }
2764       case SMDSEntity_BiQuad_Triangle: // TRIA7
2765       {
2766         elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
2767         nbElems = 3;
2768         nbNodes = 4;
2769         elemType = & quadType;
2770
2771         // get nodes for new elements
2772         static int fInd[3][4] = {{ 0,3,6,5 }, { 1,4,6,3 }, { 2,5,6,4 }};
2773         selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes );
2774
2775         // add boundary segments to elemQueue
2776         static int eInd[3][3] = {{ 0,1,3 }, { 1,2,4 }, { 2,0,5 }};
2777         selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 3,3, mesh, &elemQueue, SMDSAbs_Edge );
2778         break;
2779       }
2780       case SMDSEntity_BiQuad_Quadrangle: // QUAD9
2781       {
2782         elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
2783         nbElems = 4;
2784         nbNodes = 4;
2785         elemType = & quadType;
2786
2787         // get nodes for new elements
2788         static int fInd[4][4] = {{ 0,4,8,7 }, { 1,5,8,4 }, { 2,6,8,5 }, { 3,7,8,6 }};
2789         selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes );
2790
2791         // add boundary segments to elemQueue
2792         static int eInd[4][3] = {{ 0,1,4 }, { 1,2,5 }, { 2,3,6 }, { 3,0,7 }};
2793         selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 4,3, mesh, &elemQueue, SMDSAbs_Edge );
2794         break;
2795       }
2796       case SMDSEntity_Quad_Edge:
2797       {
2798         if ( elemIt == elemQueue.begin() )
2799           continue; // an elem is in theElems
2800         elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
2801         nbElems = 2;
2802         nbNodes = 2;
2803         elemType = & segType;
2804
2805         // get nodes for new elements
2806         static int eInd[2][2] = {{ 0,2 }, { 2,1 }};
2807         selectNodes( elemNodes, & splitNodes[0], &eInd[0][0], nbElems, nbNodes );
2808         break;
2809       }
2810       default: continue;
2811       } // switch( elem->GetEntityType() )
2812
2813       // Create new elements
2814
2815       SMESHDS_SubMesh* subMesh = mesh->MeshElements( elem->getshapeId() );
2816
2817       splitElems.clear();
2818
2819       //elemType->SetID( elem->GetID() ); // create an elem with the same ID as a removed one
2820       mesh->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false );
2821       //splitElems.push_back( AddElement( splitNodes[ 0 ], *elemType ));
2822       //elemType->SetID( -1 );
2823
2824       for ( int iE = 0; iE < nbElems; ++iE )
2825         splitElems.push_back( AddElement( splitNodes[ iE ], *elemType ));
2826
2827
2828       ReplaceElemInGroups( elem, splitElems, mesh );
2829
2830       if ( subMesh )
2831         for ( size_t i = 0; i < splitElems.size(); ++i )
2832           subMesh->AddElement( splitElems[i] );
2833     }
2834   }
2835 }
2836
2837 //=======================================================================
2838 //function : AddToSameGroups
2839 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
2840 //=======================================================================
2841
2842 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
2843                                         const SMDS_MeshElement* elemInGroups,
2844                                         SMESHDS_Mesh *          aMesh)
2845 {
2846   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2847   if (!groups.empty()) {
2848     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2849     for ( ; grIt != groups.end(); grIt++ ) {
2850       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2851       if ( group && group->Contains( elemInGroups ))
2852         group->SMDSGroup().Add( elemToAdd );
2853     }
2854   }
2855 }
2856
2857
2858 //=======================================================================
2859 //function : RemoveElemFromGroups
2860 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
2861 //=======================================================================
2862 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
2863                                              SMESHDS_Mesh *          aMesh)
2864 {
2865   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2866   if (!groups.empty())
2867   {
2868     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
2869     for (; GrIt != groups.end(); GrIt++)
2870     {
2871       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
2872       if (!grp || grp->IsEmpty()) continue;
2873       grp->SMDSGroup().Remove(removeelem);
2874     }
2875   }
2876 }
2877
2878 //================================================================================
2879 /*!
2880  * \brief Replace elemToRm by elemToAdd in the all groups
2881  */
2882 //================================================================================
2883
2884 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
2885                                             const SMDS_MeshElement* elemToAdd,
2886                                             SMESHDS_Mesh *          aMesh)
2887 {
2888   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2889   if (!groups.empty()) {
2890     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2891     for ( ; grIt != groups.end(); grIt++ ) {
2892       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2893       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
2894         group->SMDSGroup().Add( elemToAdd );
2895     }
2896   }
2897 }
2898
2899 //================================================================================
2900 /*!
2901  * \brief Replace elemToRm by elemToAdd in the all groups
2902  */
2903 //================================================================================
2904
2905 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
2906                                             const vector<const SMDS_MeshElement*>& elemToAdd,
2907                                             SMESHDS_Mesh *                         aMesh)
2908 {
2909   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2910   if (!groups.empty())
2911   {
2912     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2913     for ( ; grIt != groups.end(); grIt++ ) {
2914       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2915       if ( group && group->SMDSGroup().Remove( elemToRm ) )
2916         for ( int i = 0; i < elemToAdd.size(); ++i )
2917           group->SMDSGroup().Add( elemToAdd[ i ] );
2918     }
2919   }
2920 }
2921
2922 //=======================================================================
2923 //function : QuadToTri
2924 //purpose  : Cut quadrangles into triangles.
2925 //           theCrit is used to select a diagonal to cut
2926 //=======================================================================
2927
2928 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
2929                                   const bool         the13Diag)
2930 {
2931   myLastCreatedElems.Clear();
2932   myLastCreatedNodes.Clear();
2933
2934   MESSAGE( "::QuadToTri()" );
2935
2936   SMESHDS_Mesh * aMesh = GetMeshDS();
2937
2938   Handle(Geom_Surface) surface;
2939   SMESH_MesherHelper   helper( *GetMesh() );
2940
2941   TIDSortedElemSet::iterator itElem;
2942   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2943     const SMDS_MeshElement* elem = *itElem;
2944     if ( !elem || elem->GetType() != SMDSAbs_Face )
2945       continue;
2946     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
2947     if(!isquad) continue;
2948
2949     if(elem->NbNodes()==4) {
2950       // retrieve element nodes
2951       const SMDS_MeshNode* aNodes [4];
2952       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2953       int i = 0;
2954       while ( itN->more() )
2955         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2956
2957       int aShapeId = FindShape( elem );
2958       const SMDS_MeshElement* newElem1 = 0;
2959       const SMDS_MeshElement* newElem2 = 0;
2960       if ( the13Diag ) {
2961         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
2962         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
2963       }
2964       else {
2965         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
2966         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
2967       }
2968       myLastCreatedElems.Append(newElem1);
2969       myLastCreatedElems.Append(newElem2);
2970       // put a new triangle on the same shape and add to the same groups
2971       if ( aShapeId )
2972         {
2973           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2974           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2975         }
2976       AddToSameGroups( newElem1, elem, aMesh );
2977       AddToSameGroups( newElem2, elem, aMesh );
2978       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
2979       aMesh->RemoveElement( elem );
2980     }
2981
2982     // Quadratic quadrangle
2983
2984     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
2985
2986       // get surface elem is on
2987       int aShapeId = FindShape( elem );
2988       if ( aShapeId != helper.GetSubShapeID() ) {
2989         surface.Nullify();
2990         TopoDS_Shape shape;
2991         if ( aShapeId > 0 )
2992           shape = aMesh->IndexToShape( aShapeId );
2993         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
2994           TopoDS_Face face = TopoDS::Face( shape );
2995           surface = BRep_Tool::Surface( face );
2996           if ( !surface.IsNull() )
2997             helper.SetSubShape( shape );
2998         }
2999       }
3000
3001       const SMDS_MeshNode* aNodes [8];
3002       const SMDS_MeshNode* inFaceNode = 0;
3003       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3004       int i = 0;
3005       while ( itN->more() ) {
3006         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
3007         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
3008              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
3009         {
3010           inFaceNode = aNodes[ i-1 ];
3011         }
3012       }
3013
3014       // find middle point for (0,1,2,3)
3015       // and create a node in this point;
3016       gp_XYZ p( 0,0,0 );
3017       if ( surface.IsNull() ) {
3018         for(i=0; i<4; i++)
3019           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
3020         p /= 4;
3021       }
3022       else {
3023         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
3024         gp_XY uv( 0,0 );
3025         for(i=0; i<4; i++)
3026           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
3027         uv /= 4.;
3028         p = surface->Value( uv.X(), uv.Y() ).XYZ();
3029       }
3030       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
3031       myLastCreatedNodes.Append(newN);
3032
3033       // create a new element
3034       const SMDS_MeshElement* newElem1 = 0;
3035       const SMDS_MeshElement* newElem2 = 0;
3036       if ( the13Diag ) {
3037         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
3038                                   aNodes[6], aNodes[7], newN );
3039         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
3040                                   newN,      aNodes[4], aNodes[5] );
3041       }
3042       else {
3043         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
3044                                   aNodes[7], aNodes[4], newN );
3045         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
3046                                   newN,      aNodes[5], aNodes[6] );
3047       }
3048       myLastCreatedElems.Append(newElem1);
3049       myLastCreatedElems.Append(newElem2);
3050       // put a new triangle on the same shape and add to the same groups
3051       if ( aShapeId )
3052         {
3053           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
3054           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
3055         }
3056       AddToSameGroups( newElem1, elem, aMesh );
3057       AddToSameGroups( newElem2, elem, aMesh );
3058       aMesh->RemoveElement( elem );
3059     }
3060   }
3061
3062   return true;
3063 }
3064
3065 //=======================================================================
3066 //function : getAngle
3067 //purpose  :
3068 //=======================================================================
3069
3070 double getAngle(const SMDS_MeshElement * tr1,
3071                 const SMDS_MeshElement * tr2,
3072                 const SMDS_MeshNode *    n1,
3073                 const SMDS_MeshNode *    n2)
3074 {
3075   double angle = 2. * M_PI; // bad angle
3076
3077   // get normals
3078   SMESH::Controls::TSequenceOfXYZ P1, P2;
3079   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
3080        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
3081     return angle;
3082   gp_Vec N1,N2;
3083   if(!tr1->IsQuadratic())
3084     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
3085   else
3086     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
3087   if ( N1.SquareMagnitude() <= gp::Resolution() )
3088     return angle;
3089   if(!tr2->IsQuadratic())
3090     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
3091   else
3092     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
3093   if ( N2.SquareMagnitude() <= gp::Resolution() )
3094     return angle;
3095
3096   // find the first diagonal node n1 in the triangles:
3097   // take in account a diagonal link orientation
3098   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
3099   for ( int t = 0; t < 2; t++ ) {
3100     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
3101     int i = 0, iDiag = -1;
3102     while ( it->more()) {
3103       const SMDS_MeshElement *n = it->next();
3104       if ( n == n1 || n == n2 ) {
3105         if ( iDiag < 0)
3106           iDiag = i;
3107         else {
3108           if ( i - iDiag == 1 )
3109             nFirst[ t ] = ( n == n1 ? n2 : n1 );
3110           else
3111             nFirst[ t ] = n;
3112           break;
3113         }
3114       }
3115       i++;
3116     }
3117   }
3118   if ( nFirst[ 0 ] == nFirst[ 1 ] )
3119     N2.Reverse();
3120
3121   angle = N1.Angle( N2 );
3122   //SCRUTE( angle );
3123   return angle;
3124 }
3125
3126 // =================================================
3127 // class generating a unique ID for a pair of nodes
3128 // and able to return nodes by that ID
3129 // =================================================
3130 class LinkID_Gen {
3131 public:
3132
3133   LinkID_Gen( const SMESHDS_Mesh* theMesh )
3134     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
3135   {}
3136
3137   long GetLinkID (const SMDS_MeshNode * n1,
3138                   const SMDS_MeshNode * n2) const
3139   {
3140     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
3141   }
3142
3143   bool GetNodes (const long             theLinkID,
3144                  const SMDS_MeshNode* & theNode1,
3145                  const SMDS_MeshNode* & theNode2) const
3146   {
3147     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
3148     if ( !theNode1 ) return false;
3149     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
3150     if ( !theNode2 ) return false;
3151     return true;
3152   }
3153
3154 private:
3155   LinkID_Gen();
3156   const SMESHDS_Mesh* myMesh;
3157   long                myMaxID;
3158 };
3159
3160
3161 //=======================================================================
3162 //function : TriToQuad
3163 //purpose  : Fuse neighbour triangles into quadrangles.
3164 //           theCrit is used to select a neighbour to fuse with.
3165 //           theMaxAngle is a max angle between element normals at which
3166 //           fusion is still performed.
3167 //=======================================================================
3168
3169 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
3170                                   SMESH::Controls::NumericalFunctorPtr theCrit,
3171                                   const double                         theMaxAngle)
3172 {
3173   myLastCreatedElems.Clear();
3174   myLastCreatedNodes.Clear();
3175
3176   MESSAGE( "::TriToQuad()" );
3177
3178   if ( !theCrit.get() )
3179     return false;
3180
3181   SMESHDS_Mesh * aMesh = GetMeshDS();
3182
3183   // Prepare data for algo: build
3184   // 1. map of elements with their linkIDs
3185   // 2. map of linkIDs with their elements
3186
3187   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
3188   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
3189   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
3190   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
3191
3192   TIDSortedElemSet::iterator itElem;
3193   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
3194   {
3195     const SMDS_MeshElement* elem = *itElem;
3196     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
3197     bool IsTria = ( elem->NbCornerNodes()==3 );
3198     if (!IsTria) continue;
3199
3200     // retrieve element nodes
3201     const SMDS_MeshNode* aNodes [4];
3202     SMDS_NodeIteratorPtr itN = elem->nodeIterator();
3203     int i = 0;
3204     while ( i < 3 )
3205       aNodes[ i++ ] = itN->next();
3206     aNodes[ 3 ] = aNodes[ 0 ];
3207
3208     // fill maps
3209     for ( i = 0; i < 3; i++ ) {
3210       SMESH_TLink link( aNodes[i], aNodes[i+1] );
3211       // check if elements sharing a link can be fused
3212       itLE = mapLi_listEl.find( link );
3213       if ( itLE != mapLi_listEl.end() ) {
3214         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
3215           continue;
3216         const SMDS_MeshElement* elem2 = (*itLE).second.front();
3217         //if ( FindShape( elem ) != FindShape( elem2 ))
3218         //  continue; // do not fuse triangles laying on different shapes
3219         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
3220           continue; // avoid making badly shaped quads
3221         (*itLE).second.push_back( elem );
3222       }
3223       else {
3224         mapLi_listEl[ link ].push_back( elem );
3225       }
3226       mapEl_setLi [ elem ].insert( link );
3227     }
3228   }
3229   // Clean the maps from the links shared by a sole element, ie
3230   // links to which only one element is bound in mapLi_listEl
3231
3232   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
3233     int nbElems = (*itLE).second.size();
3234     if ( nbElems < 2  ) {
3235       const SMDS_MeshElement* elem = (*itLE).second.front();
3236       SMESH_TLink link = (*itLE).first;
3237       mapEl_setLi[ elem ].erase( link );
3238       if ( mapEl_setLi[ elem ].empty() )
3239         mapEl_setLi.erase( elem );
3240     }
3241   }
3242
3243   // Algo: fuse triangles into quadrangles
3244
3245   while ( ! mapEl_setLi.empty() ) {
3246     // Look for the start element:
3247     // the element having the least nb of shared links
3248     const SMDS_MeshElement* startElem = 0;
3249     int minNbLinks = 4;
3250     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
3251       int nbLinks = (*itEL).second.size();
3252       if ( nbLinks < minNbLinks ) {
3253         startElem = (*itEL).first;
3254         minNbLinks = nbLinks;
3255         if ( minNbLinks == 1 )
3256           break;
3257       }
3258     }
3259
3260     // search elements to fuse starting from startElem or links of elements
3261     // fused earlyer - startLinks
3262     list< SMESH_TLink > startLinks;
3263     while ( startElem || !startLinks.empty() ) {
3264       while ( !startElem && !startLinks.empty() ) {
3265         // Get an element to start, by a link
3266         SMESH_TLink linkId = startLinks.front();
3267         startLinks.pop_front();
3268         itLE = mapLi_listEl.find( linkId );
3269         if ( itLE != mapLi_listEl.end() ) {
3270           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
3271           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
3272           for ( ; itE != listElem.end() ; itE++ )
3273             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
3274               startElem = (*itE);
3275           mapLi_listEl.erase( itLE );
3276         }
3277       }
3278
3279       if ( startElem ) {
3280         // Get candidates to be fused
3281         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
3282         const SMESH_TLink *link12, *link13;
3283         startElem = 0;
3284         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
3285         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
3286         ASSERT( !setLi.empty() );
3287         set< SMESH_TLink >::iterator itLi;
3288         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
3289         {
3290           const SMESH_TLink & link = (*itLi);
3291           itLE = mapLi_listEl.find( link );
3292           if ( itLE == mapLi_listEl.end() )
3293             continue;
3294
3295           const SMDS_MeshElement* elem = (*itLE).second.front();
3296           if ( elem == tr1 )
3297             elem = (*itLE).second.back();
3298           mapLi_listEl.erase( itLE );
3299           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
3300             continue;
3301           if ( tr2 ) {
3302             tr3 = elem;
3303             link13 = &link;
3304           }
3305           else {
3306             tr2 = elem;
3307             link12 = &link;
3308           }
3309
3310           // add other links of elem to list of links to re-start from
3311           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
3312           set< SMESH_TLink >::iterator it;
3313           for ( it = links.begin(); it != links.end(); it++ ) {
3314             const SMESH_TLink& link2 = (*it);
3315             if ( link2 != link )
3316               startLinks.push_back( link2 );
3317           }
3318         }
3319
3320         // Get nodes of possible quadrangles
3321         const SMDS_MeshNode *n12 [4], *n13 [4];
3322         bool Ok12 = false, Ok13 = false;
3323         const SMDS_MeshNode *linkNode1, *linkNode2;
3324         if(tr2) {
3325           linkNode1 = link12->first;
3326           linkNode2 = link12->second;
3327           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
3328             Ok12 = true;
3329         }
3330         if(tr3) {
3331           linkNode1 = link13->first;
3332           linkNode2 = link13->second;
3333           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
3334             Ok13 = true;
3335         }
3336
3337         // Choose a pair to fuse
3338         if ( Ok12 && Ok13 ) {
3339           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
3340           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
3341           double aBadRate12 = getBadRate( &quad12, theCrit );
3342           double aBadRate13 = getBadRate( &quad13, theCrit );
3343           if (  aBadRate13 < aBadRate12 )
3344             Ok12 = false;
3345           else
3346             Ok13 = false;
3347         }
3348
3349         // Make quadrangles
3350         // and remove fused elems and remove links from the maps
3351         mapEl_setLi.erase( tr1 );
3352         if ( Ok12 )
3353         {
3354           mapEl_setLi.erase( tr2 );
3355           mapLi_listEl.erase( *link12 );
3356           if ( tr1->NbNodes() == 3 )
3357           {
3358             const SMDS_MeshElement* newElem = 0;
3359             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
3360             myLastCreatedElems.Append(newElem);
3361             AddToSameGroups( newElem, tr1, aMesh );
3362             int aShapeId = tr1->getshapeId();
3363             if ( aShapeId )
3364               aMesh->SetMeshElementOnShape( newElem, aShapeId );
3365             aMesh->RemoveElement( tr1 );
3366             aMesh->RemoveElement( tr2 );
3367           }
3368           else {
3369             vector< const SMDS_MeshNode* > N1;
3370             vector< const SMDS_MeshNode* > N2;
3371             getNodesFromTwoTria(tr1,tr2,N1,N2);
3372             // now we receive following N1 and N2 (using numeration as in image in InverseDiag())
3373             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
3374             // i.e. first nodes from both arrays form a new diagonal
3375             const SMDS_MeshNode* aNodes[8];
3376             aNodes[0] = N1[0];
3377             aNodes[1] = N1[1];
3378             aNodes[2] = N2[0];
3379             aNodes[3] = N2[1];
3380             aNodes[4] = N1[3];
3381             aNodes[5] = N2[5];
3382             aNodes[6] = N2[3];
3383             aNodes[7] = N1[5];
3384             const SMDS_MeshElement* newElem = 0;
3385             if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
3386               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
3387                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
3388             else
3389               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
3390                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
3391             myLastCreatedElems.Append(newElem);
3392             AddToSameGroups( newElem, tr1, aMesh );
3393             int aShapeId = tr1->getshapeId();
3394             if ( aShapeId )
3395               aMesh->SetMeshElementOnShape( newElem, aShapeId );
3396             aMesh->RemoveElement( tr1 );
3397             aMesh->RemoveElement( tr2 );
3398             // remove middle node (9)
3399             if ( N1[4]->NbInverseElements() == 0 )
3400               aMesh->RemoveNode( N1[4] );
3401             if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
3402               aMesh->RemoveNode( N1[6] );
3403             if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
3404               aMesh->RemoveNode( N2[6] );
3405           }
3406         }
3407         else if ( Ok13 )
3408         {
3409           mapEl_setLi.erase( tr3 );
3410           mapLi_listEl.erase( *link13 );
3411           if ( tr1->NbNodes() == 3 ) {
3412             const SMDS_MeshElement* newElem = 0;
3413             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
3414             myLastCreatedElems.Append(newElem);
3415             AddToSameGroups( newElem, tr1, aMesh );
3416             int aShapeId = tr1->getshapeId();
3417             if ( aShapeId )
3418               aMesh->SetMeshElementOnShape( newElem, aShapeId );
3419             aMesh->RemoveElement( tr1 );
3420             aMesh->RemoveElement( tr3 );
3421           }
3422           else {
3423             vector< const SMDS_MeshNode* > N1;
3424             vector< const SMDS_MeshNode* > N2;
3425             getNodesFromTwoTria(tr1,tr3,N1,N2);
3426             // now we receive following N1 and N2 (using numeration as above image)
3427             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
3428             // i.e. first nodes from both arrays form a new diagonal
3429             const SMDS_MeshNode* aNodes[8];
3430             aNodes[0] = N1[0];
3431             aNodes[1] = N1[1];
3432             aNodes[2] = N2[0];
3433             aNodes[3] = N2[1];
3434             aNodes[4] = N1[3];
3435             aNodes[5] = N2[5];
3436             aNodes[6] = N2[3];
3437             aNodes[7] = N1[5];
3438             const SMDS_MeshElement* newElem = 0;
3439             if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
3440               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
3441                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
3442             else
3443               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
3444                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
3445             myLastCreatedElems.Append(newElem);
3446             AddToSameGroups( newElem, tr1, aMesh );
3447             int aShapeId = tr1->getshapeId();
3448             if ( aShapeId )
3449               aMesh->SetMeshElementOnShape( newElem, aShapeId );
3450             aMesh->RemoveElement( tr1 );
3451             aMesh->RemoveElement( tr3 );
3452             // remove middle node (9)
3453             if ( N1[4]->NbInverseElements() == 0 )
3454               aMesh->RemoveNode( N1[4] );
3455             if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
3456               aMesh->RemoveNode( N1[6] );
3457             if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
3458               aMesh->RemoveNode( N2[6] );
3459           }
3460         }
3461
3462         // Next element to fuse: the rejected one
3463         if ( tr3 )
3464           startElem = Ok12 ? tr3 : tr2;
3465
3466       } // if ( startElem )
3467     } // while ( startElem || !startLinks.empty() )
3468   } // while ( ! mapEl_setLi.empty() )
3469
3470   return true;
3471 }
3472
3473
3474 /*#define DUMPSO(txt) \
3475 //  cout << txt << endl;
3476 //=============================================================================
3477 //
3478 //
3479 //
3480 //=============================================================================
3481 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
3482 {
3483 if ( i1 == i2 )
3484 return;
3485 int tmp = idNodes[ i1 ];
3486 idNodes[ i1 ] = idNodes[ i2 ];
3487 idNodes[ i2 ] = tmp;
3488 gp_Pnt Ptmp = P[ i1 ];
3489 P[ i1 ] = P[ i2 ];
3490 P[ i2 ] = Ptmp;
3491 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
3492 }
3493
3494 //=======================================================================
3495 //function : SortQuadNodes
3496 //purpose  : Set 4 nodes of a quadrangle face in a good order.
3497 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
3498 //           1 or 2 else 0.
3499 //=======================================================================
3500
3501 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
3502 int               idNodes[] )
3503 {
3504   gp_Pnt P[4];
3505   int i;
3506   for ( i = 0; i < 4; i++ ) {
3507     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
3508     if ( !n ) return 0;
3509     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
3510   }
3511
3512   gp_Vec V1(P[0], P[1]);
3513   gp_Vec V2(P[0], P[2]);
3514   gp_Vec V3(P[0], P[3]);
3515
3516   gp_Vec Cross1 = V1 ^ V2;
3517   gp_Vec Cross2 = V2 ^ V3;
3518
3519   i = 0;
3520   if (Cross1.Dot(Cross2) < 0)
3521   {
3522     Cross1 = V2 ^ V1;
3523     Cross2 = V1 ^ V3;
3524
3525     if (Cross1.Dot(Cross2) < 0)
3526       i = 2;
3527     else
3528       i = 1;
3529     swap ( i, i + 1, idNodes, P );
3530
3531     //     for ( int ii = 0; ii < 4; ii++ ) {
3532     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
3533     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
3534     //     }
3535   }
3536   return i;
3537 }
3538
3539 //=======================================================================
3540 //function : SortHexaNodes
3541 //purpose  : Set 8 nodes of a hexahedron in a good order.
3542 //           Return success status
3543 //=======================================================================
3544
3545 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
3546                                       int               idNodes[] )
3547 {
3548   gp_Pnt P[8];
3549   int i;
3550   DUMPSO( "INPUT: ========================================");
3551   for ( i = 0; i < 8; i++ ) {
3552     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
3553     if ( !n ) return false;
3554     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
3555     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
3556   }
3557   DUMPSO( "========================================");
3558
3559
3560   set<int> faceNodes;  // ids of bottom face nodes, to be found
3561   set<int> checkedId1; // ids of tried 2-nd nodes
3562   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
3563   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
3564   int iMin, iLoop1 = 0;
3565
3566   // Loop to try the 2-nd nodes
3567
3568   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
3569   {
3570     // Find not checked 2-nd node
3571     for ( i = 1; i < 8; i++ )
3572       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
3573         int id1 = idNodes[i];
3574         swap ( 1, i, idNodes, P );
3575         checkedId1.insert ( id1 );
3576         break;
3577       }
3578
3579     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
3580     // ie that all but meybe one (id3 which is on the same face) nodes
3581     // lay on the same side from the triangle plane.
3582
3583     bool manyInPlane = false; // more than 4 nodes lay in plane
3584     int iLoop2 = 0;
3585     while ( ++iLoop2 < 6 ) {
3586
3587       // get 1-2-3 plane coeffs
3588       Standard_Real A, B, C, D;
3589       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
3590       if ( N.SquareMagnitude() > gp::Resolution() )
3591       {
3592         gp_Pln pln ( P[0], N );
3593         pln.Coefficients( A, B, C, D );
3594
3595         // find the node (iMin) closest to pln
3596         Standard_Real dist[ 8 ], minDist = DBL_MAX;
3597         set<int> idInPln;
3598         for ( i = 3; i < 8; i++ ) {
3599           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
3600           if ( fabs( dist[i] ) < minDist ) {
3601             minDist = fabs( dist[i] );
3602             iMin = i;
3603           }
3604           if ( fabs( dist[i] ) <= tol )
3605             idInPln.insert( idNodes[i] );
3606         }
3607
3608         // there should not be more than 4 nodes in bottom plane
3609         if ( idInPln.size() > 1 )
3610         {
3611           DUMPSO( "### idInPln.size() = " << idInPln.size());
3612           // idInPlane does not contain the first 3 nodes
3613           if ( manyInPlane || idInPln.size() == 5)
3614             return false; // all nodes in one plane
3615           manyInPlane = true;
3616
3617           // set the 1-st node to be not in plane
3618           for ( i = 3; i < 8; i++ ) {
3619             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
3620               DUMPSO( "### Reset 0-th node");
3621               swap( 0, i, idNodes, P );
3622               break;
3623             }
3624           }
3625
3626           // reset to re-check second nodes
3627           leastDist = DBL_MAX;
3628           faceNodes.clear();
3629           checkedId1.clear();
3630           iLoop1 = 0;
3631           break; // from iLoop2;
3632         }
3633
3634         // check that the other 4 nodes are on the same side
3635         bool sameSide = true;
3636         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
3637         for ( i = 3; sameSide && i < 8; i++ ) {
3638           if ( i != iMin )
3639             sameSide = ( isNeg == dist[i] <= 0.);
3640         }
3641
3642         // keep best solution
3643         if ( sameSide && minDist < leastDist ) {
3644           leastDist = minDist;
3645           faceNodes.clear();
3646           faceNodes.insert( idNodes[ 1 ] );
3647           faceNodes.insert( idNodes[ 2 ] );
3648           faceNodes.insert( idNodes[ iMin ] );
3649           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
3650                   << " leastDist = " << leastDist);
3651           if ( leastDist <= DBL_MIN )
3652             break;
3653         }
3654       }
3655
3656       // set next 3-d node to check
3657       int iNext = 2 + iLoop2;
3658       if ( iNext < 8 ) {
3659         DUMPSO( "Try 2-nd");
3660         swap ( 2, iNext, idNodes, P );
3661       }
3662     } // while ( iLoop2 < 6 )
3663   } // iLoop1
3664
3665   if ( faceNodes.empty() ) return false;
3666
3667   // Put the faceNodes in proper places
3668   for ( i = 4; i < 8; i++ ) {
3669     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
3670       // find a place to put
3671       int iTo = 1;
3672       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
3673         iTo++;
3674       DUMPSO( "Set faceNodes");
3675       swap ( iTo, i, idNodes, P );
3676     }
3677   }
3678
3679
3680   // Set nodes of the found bottom face in good order
3681   DUMPSO( " Found bottom face: ");
3682   i = SortQuadNodes( theMesh, idNodes );
3683   if ( i ) {
3684     gp_Pnt Ptmp = P[ i ];
3685     P[ i ] = P[ i+1 ];
3686     P[ i+1 ] = Ptmp;
3687   }
3688   //   else
3689   //     for ( int ii = 0; ii < 4; ii++ ) {
3690   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
3691   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
3692   //    }
3693
3694   // Gravity center of the top and bottom faces
3695   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
3696   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
3697
3698   // Get direction from the bottom to the top face
3699   gp_Vec upDir ( aGCb, aGCt );
3700   Standard_Real upDirSize = upDir.Magnitude();
3701   if ( upDirSize <= gp::Resolution() ) return false;
3702   upDir / upDirSize;
3703
3704   // Assure that the bottom face normal points up
3705   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
3706   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
3707   if ( Nb.Dot( upDir ) < 0 ) {
3708     DUMPSO( "Reverse bottom face");
3709     swap( 1, 3, idNodes, P );
3710   }
3711
3712   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
3713   Standard_Real minDist = DBL_MAX;
3714   for ( i = 4; i < 8; i++ ) {
3715     // projection of P[i] to the plane defined by P[0] and upDir
3716     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
3717     Standard_Real sqDist = P[0].SquareDistance( Pp );
3718     if ( sqDist < minDist ) {
3719       minDist = sqDist;
3720       iMin = i;
3721     }
3722   }
3723   DUMPSO( "Set 4-th");
3724   swap ( 4, iMin, idNodes, P );
3725
3726   // Set nodes of the top face in good order
3727   DUMPSO( "Sort top face");
3728   i = SortQuadNodes( theMesh, &idNodes[4] );
3729   if ( i ) {
3730     i += 4;
3731     gp_Pnt Ptmp = P[ i ];
3732     P[ i ] = P[ i+1 ];
3733     P[ i+1 ] = Ptmp;
3734   }
3735
3736   // Assure that direction of the top face normal is from the bottom face
3737   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
3738   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
3739   if ( Nt.Dot( upDir ) < 0 ) {
3740     DUMPSO( "Reverse top face");
3741     swap( 5, 7, idNodes, P );
3742   }
3743
3744   //   DUMPSO( "OUTPUT: ========================================");
3745   //   for ( i = 0; i < 8; i++ ) {
3746   //     float *p = ugrid->GetPoint(idNodes[i]);
3747   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
3748   //   }
3749
3750   return true;
3751 }*/
3752
3753 //================================================================================
3754 /*!
3755  * \brief Return nodes linked to the given one
3756  * \param theNode - the node
3757  * \param linkedNodes - the found nodes
3758  * \param type - the type of elements to check
3759  *
3760  * Medium nodes are ignored
3761  */
3762 //================================================================================
3763
3764 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
3765                                        TIDSortedElemSet &   linkedNodes,
3766                                        SMDSAbs_ElementType  type )
3767 {
3768   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
3769   while ( elemIt->more() )
3770   {
3771     const SMDS_MeshElement* elem = elemIt->next();
3772     if(elem->GetType() == SMDSAbs_0DElement)
3773       continue;
3774
3775     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
3776     if ( elem->GetType() == SMDSAbs_Volume )
3777     {
3778       SMDS_VolumeTool vol( elem );
3779       while ( nodeIt->more() ) {
3780         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
3781         if ( theNode != n && vol.IsLinked( theNode, n ))
3782           linkedNodes.insert( n );
3783       }
3784     }
3785     else
3786     {
3787       for ( int i = 0; nodeIt->more(); ++i ) {
3788         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
3789         if ( n == theNode ) {
3790           int iBefore = i - 1;
3791           int iAfter  = i + 1;
3792           if ( elem->IsQuadratic() ) {
3793             int nb = elem->NbNodes() / 2;
3794             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
3795             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
3796           }
3797           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
3798           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
3799         }
3800       }
3801     }
3802   }
3803 }
3804
3805 //=======================================================================
3806 //function : laplacianSmooth
3807 //purpose  : pulls theNode toward the center of surrounding nodes directly
3808 //           connected to that node along an element edge
3809 //=======================================================================
3810
3811 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
3812                      const Handle(Geom_Surface)&          theSurface,
3813                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3814 {
3815   // find surrounding nodes
3816
3817   TIDSortedElemSet nodeSet;
3818   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
3819
3820   // compute new coodrs
3821
3822   double coord[] = { 0., 0., 0. };
3823   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
3824   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
3825     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
3826     if ( theSurface.IsNull() ) { // smooth in 3D
3827       coord[0] += node->X();
3828       coord[1] += node->Y();
3829       coord[2] += node->Z();
3830     }
3831     else { // smooth in 2D
3832       ASSERT( theUVMap.find( node ) != theUVMap.end() );
3833       gp_XY* uv = theUVMap[ node ];
3834       coord[0] += uv->X();
3835       coord[1] += uv->Y();
3836     }
3837   }
3838   int nbNodes = nodeSet.size();
3839   if ( !nbNodes )
3840     return;
3841   coord[0] /= nbNodes;
3842   coord[1] /= nbNodes;
3843
3844   if ( !theSurface.IsNull() ) {
3845     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
3846     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
3847     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
3848     coord[0] = p3d.X();
3849     coord[1] = p3d.Y();
3850     coord[2] = p3d.Z();
3851   }
3852   else
3853     coord[2] /= nbNodes;
3854
3855   // move node
3856
3857   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
3858 }
3859
3860 //=======================================================================
3861 //function : centroidalSmooth
3862 //purpose  : pulls theNode toward the element-area-weighted centroid of the
3863 //           surrounding elements
3864 //=======================================================================
3865
3866 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
3867                       const Handle(Geom_Surface)&          theSurface,
3868                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3869 {
3870   gp_XYZ aNewXYZ(0.,0.,0.);
3871   SMESH::Controls::Area anAreaFunc;
3872   double totalArea = 0.;
3873   int nbElems = 0;
3874
3875   // compute new XYZ
3876
3877   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
3878   while ( elemIt->more() )
3879   {
3880     const SMDS_MeshElement* elem = elemIt->next();
3881     nbElems++;
3882
3883     gp_XYZ elemCenter(0.,0.,0.);
3884     SMESH::Controls::TSequenceOfXYZ aNodePoints;
3885     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3886     int nn = elem->NbNodes();
3887     if(elem->IsQuadratic()) nn = nn/2;
3888     int i=0;
3889     //while ( itN->more() ) {
3890     while ( i<nn ) {
3891       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
3892       i++;
3893       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
3894       aNodePoints.push_back( aP );
3895       if ( !theSurface.IsNull() ) { // smooth in 2D
3896         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
3897         gp_XY* uv = theUVMap[ aNode ];
3898         aP.SetCoord( uv->X(), uv->Y(), 0. );
3899       }
3900       elemCenter += aP;
3901     }
3902     double elemArea = anAreaFunc.GetValue( aNodePoints );
3903     totalArea += elemArea;
3904     elemCenter /= nn;
3905     aNewXYZ += elemCenter * elemArea;
3906   }
3907   aNewXYZ /= totalArea;
3908   if ( !theSurface.IsNull() ) {
3909     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
3910     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
3911   }
3912
3913   // move node
3914
3915   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
3916 }
3917
3918 //=======================================================================
3919 //function : getClosestUV
3920 //purpose  : return UV of closest projection
3921 //=======================================================================
3922
3923 static bool getClosestUV (Extrema_GenExtPS& projector,
3924                           const gp_Pnt&     point,
3925                           gp_XY &           result)
3926 {
3927   projector.Perform( point );
3928   if ( projector.IsDone() ) {
3929     double u, v, minVal = DBL_MAX;
3930     for ( int i = projector.NbExt(); i > 0; i-- )
3931       if ( projector.SquareDistance( i ) < minVal ) {
3932         minVal = projector.SquareDistance( i );
3933         projector.Point( i ).Parameter( u, v );
3934       }
3935     result.SetCoord( u, v );
3936     return true;
3937   }
3938   return false;
3939 }
3940
3941 //=======================================================================
3942 //function : Smooth
3943 //purpose  : Smooth theElements during theNbIterations or until a worst
3944 //           element has aspect ratio <= theTgtAspectRatio.
3945 //           Aspect Ratio varies in range [1.0, inf].
3946 //           If theElements is empty, the whole mesh is smoothed.
3947 //           theFixedNodes contains additionally fixed nodes. Nodes built
3948 //           on edges and boundary nodes are always fixed.
3949 //=======================================================================
3950
3951 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
3952                                set<const SMDS_MeshNode*> & theFixedNodes,
3953                                const SmoothMethod          theSmoothMethod,
3954                                const int                   theNbIterations,
3955                                double                      theTgtAspectRatio,
3956                                const bool                  the2D)
3957 {
3958   myLastCreatedElems.Clear();
3959   myLastCreatedNodes.Clear();
3960
3961   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
3962
3963   if ( theTgtAspectRatio < 1.0 )
3964     theTgtAspectRatio = 1.0;
3965
3966   const double disttol = 1.e-16;
3967
3968   SMESH::Controls::AspectRatio aQualityFunc;
3969
3970   SMESHDS_Mesh* aMesh = GetMeshDS();
3971
3972   if ( theElems.empty() ) {
3973     // add all faces to theElems
3974     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
3975     while ( fIt->more() ) {
3976       const SMDS_MeshElement* face = fIt->next();
3977       theElems.insert( theElems.end(), face );
3978     }
3979   }
3980   // get all face ids theElems are on
3981   set< int > faceIdSet;
3982   TIDSortedElemSet::iterator itElem;
3983   if ( the2D )
3984     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3985       int fId = FindShape( *itElem );
3986       // check that corresponding submesh exists and a shape is face
3987       if (fId &&
3988           faceIdSet.find( fId ) == faceIdSet.end() &&
3989           aMesh->MeshElements( fId )) {
3990         TopoDS_Shape F = aMesh->IndexToShape( fId );
3991         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
3992           faceIdSet.insert( fId );
3993       }
3994     }
3995   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
3996
3997   // ===============================================
3998   // smooth elements on each TopoDS_Face separately
3999   // ===============================================
4000
4001   SMESH_MesherHelper helper( *GetMesh() );
4002
4003   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treat 0 fId at the end
4004   for ( ; fId != faceIdSet.rend(); ++fId )
4005   {
4006     // get face surface and submesh
4007     Handle(Geom_Surface) surface;
4008     SMESHDS_SubMesh* faceSubMesh = 0;
4009     TopoDS_Face face;
4010     double fToler2 = 0, f,l;
4011     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
4012     bool isUPeriodic = false, isVPeriodic = false;
4013     if ( *fId )
4014     {
4015       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
4016       surface = BRep_Tool::Surface( face );
4017       faceSubMesh = aMesh->MeshElements( *fId );
4018       fToler2 = BRep_Tool::Tolerance( face );
4019       fToler2 *= fToler2 * 10.;
4020       isUPeriodic = surface->IsUPeriodic();
4021       if ( isUPeriodic )
4022         surface->UPeriod();
4023       isVPeriodic = surface->IsVPeriodic();
4024       if ( isVPeriodic )
4025         surface->VPeriod();
4026       surface->Bounds( u1, u2, v1, v2 );
4027       helper.SetSubShape( face );
4028     }
4029     // ---------------------------------------------------------
4030     // for elements on a face, find movable and fixed nodes and
4031     // compute UV for them
4032     // ---------------------------------------------------------
4033     bool checkBoundaryNodes = false;
4034     bool isQuadratic = false;
4035     set<const SMDS_MeshNode*> setMovableNodes;
4036     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
4037     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
4038     list< const SMDS_MeshElement* > elemsOnFace;
4039
4040     Extrema_GenExtPS projector;
4041     GeomAdaptor_Surface surfAdaptor;
4042     if ( !surface.IsNull() ) {
4043       surfAdaptor.Load( surface );
4044       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
4045     }
4046     int nbElemOnFace = 0;
4047     itElem = theElems.begin();
4048     // loop on not yet smoothed elements: look for elems on a face
4049     while ( itElem != theElems.end() )
4050     {
4051       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
4052         break; // all elements found
4053
4054       const SMDS_MeshElement* elem = *itElem;
4055       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
4056            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
4057         ++itElem;
4058         continue;
4059       }
4060       elemsOnFace.push_back( elem );
4061       theElems.erase( itElem++ );
4062       nbElemOnFace++;
4063
4064       if ( !isQuadratic )
4065         isQuadratic = elem->IsQuadratic();
4066
4067       // get movable nodes of elem
4068       const SMDS_MeshNode* node;
4069       SMDS_TypeOfPosition posType;
4070       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4071       int nn = 0, nbn =  elem->NbNodes();
4072       if(elem->IsQuadratic())
4073         nbn = nbn/2;
4074       while ( nn++ < nbn ) {
4075         node = static_cast<const SMDS_MeshNode*>( itN->next() );
4076         const SMDS_PositionPtr& pos = node->GetPosition();
4077         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
4078         if (posType != SMDS_TOP_EDGE &&
4079             posType != SMDS_TOP_VERTEX &&
4080             theFixedNodes.find( node ) == theFixedNodes.end())
4081         {
4082           // check if all faces around the node are on faceSubMesh
4083           // because a node on edge may be bound to face
4084           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
4085           bool all = true;
4086           if ( faceSubMesh ) {
4087             while ( eIt->more() && all ) {
4088               const SMDS_MeshElement* e = eIt->next();
4089               all = faceSubMesh->Contains( e );
4090             }
4091           }
4092           if ( all )
4093             setMovableNodes.insert( node );
4094           else
4095             checkBoundaryNodes = true;
4096         }
4097         if ( posType == SMDS_TOP_3DSPACE )
4098           checkBoundaryNodes = true;
4099       }
4100
4101       if ( surface.IsNull() )
4102         continue;
4103
4104       // get nodes to check UV
4105       list< const SMDS_MeshNode* > uvCheckNodes;
4106       const SMDS_MeshNode* nodeInFace = 0;
4107       itN = elem->nodesIterator();
4108       nn = 0; nbn =  elem->NbNodes();
4109       if(elem->IsQuadratic())
4110         nbn = nbn/2;
4111       while ( nn++ < nbn ) {
4112         node = static_cast<const SMDS_MeshNode*>( itN->next() );
4113         if ( node->GetPosition()->GetDim() == 2 )
4114           nodeInFace = node;
4115         if ( uvMap.find( node ) == uvMap.end() )
4116           uvCheckNodes.push_back( node );
4117         // add nodes of elems sharing node
4118         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
4119         //         while ( eIt->more() ) {
4120         //           const SMDS_MeshElement* e = eIt->next();
4121         //           if ( e != elem ) {
4122         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
4123         //             while ( nIt->more() ) {
4124         //               const SMDS_MeshNode* n =
4125         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
4126         //               if ( uvMap.find( n ) == uvMap.end() )
4127         //                 uvCheckNodes.push_back( n );
4128         //             }
4129         //           }
4130         //         }
4131       }
4132       // check UV on face
4133       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
4134       for ( ; n != uvCheckNodes.end(); ++n ) {
4135         node = *n;
4136         gp_XY uv( 0, 0 );
4137         const SMDS_PositionPtr& pos = node->GetPosition();
4138         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
4139         // get existing UV
4140         if ( pos )
4141         {
4142           bool toCheck = true;
4143           uv = helper.GetNodeUV( face, node, nodeInFace, &toCheck );
4144         }
4145         // compute not existing UV
4146         bool project = ( posType == SMDS_TOP_3DSPACE );
4147         // double dist1 = DBL_MAX, dist2 = 0;
4148         // if ( posType != SMDS_TOP_3DSPACE ) {
4149         //   dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
4150         //   project = dist1 > fToler2;
4151         // }
4152         if ( project ) { // compute new UV
4153           gp_XY newUV;
4154           gp_Pnt pNode = SMESH_TNodeXYZ( node );
4155           if ( !getClosestUV( projector, pNode, newUV )) {
4156             MESSAGE("Node Projection Failed " << node);
4157           }
4158           else {
4159             if ( isUPeriodic )
4160               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
4161             if ( isVPeriodic )
4162               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
4163             // check new UV
4164             // if ( posType != SMDS_TOP_3DSPACE )
4165             //   dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
4166             // if ( dist2 < dist1 )
4167               uv = newUV;
4168           }
4169         }
4170         // store UV in the map
4171         listUV.push_back( uv );
4172         uvMap.insert( make_pair( node, &listUV.back() ));
4173       }
4174     } // loop on not yet smoothed elements
4175
4176     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
4177       checkBoundaryNodes = true;
4178
4179     // fix nodes on mesh boundary
4180
4181     if ( checkBoundaryNodes ) {
4182       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
4183       map< SMESH_TLink, int >::iterator link_nb;
4184       // put all elements links to linkNbMap
4185       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
4186       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
4187         const SMDS_MeshElement* elem = (*elemIt);
4188         int nbn =  elem->NbCornerNodes();
4189         // loop on elem links: insert them in linkNbMap
4190         for ( int iN = 0; iN < nbn; ++iN ) {
4191           const SMDS_MeshNode* n1 = elem->GetNode( iN );
4192           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
4193           SMESH_TLink link( n1, n2 );
4194           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
4195           link_nb->second++;
4196         }
4197       }
4198       // remove nodes that are in links encountered only once from setMovableNodes
4199       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
4200         if ( link_nb->second == 1 ) {
4201           setMovableNodes.erase( link_nb->first.node1() );
4202           setMovableNodes.erase( link_nb->first.node2() );
4203         }
4204       }
4205     }
4206
4207     // -----------------------------------------------------
4208     // for nodes on seam edge, compute one more UV ( uvMap2 );
4209     // find movable nodes linked to nodes on seam and which
4210     // are to be smoothed using the second UV ( uvMap2 )
4211     // -----------------------------------------------------
4212
4213     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
4214     if ( !surface.IsNull() ) {
4215       TopExp_Explorer eExp( face, TopAbs_EDGE );
4216       for ( ; eExp.More(); eExp.Next() ) {
4217         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
4218         if ( !BRep_Tool::IsClosed( edge, face ))
4219           continue;
4220         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
4221         if ( !sm ) continue;
4222         // find out which parameter varies for a node on seam
4223         double f,l;
4224         gp_Pnt2d uv1, uv2;
4225         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
4226         if ( pcurve.IsNull() ) continue;
4227         uv1 = pcurve->Value( f );
4228         edge.Reverse();
4229         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
4230         if ( pcurve.IsNull() ) continue;
4231         uv2 = pcurve->Value( f );
4232         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
4233         // assure uv1 < uv2
4234         if ( uv1.Coord( iPar ) > uv2.Coord( iPar ))
4235           std::swap( uv1, uv2 );
4236         // get nodes on seam and its vertices
4237         list< const SMDS_MeshNode* > seamNodes;
4238         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
4239         while ( nSeamIt->more() ) {
4240           const SMDS_MeshNode* node = nSeamIt->next();
4241           if ( !isQuadratic || !IsMedium( node ))
4242             seamNodes.push_back( node );
4243         }
4244         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
4245         for ( ; vExp.More(); vExp.Next() ) {
4246           sm = aMesh->MeshElements( vExp.Current() );
4247           if ( sm ) {
4248             nSeamIt = sm->GetNodes();
4249             while ( nSeamIt->more() )
4250               seamNodes.push_back( nSeamIt->next() );
4251           }
4252         }
4253         // loop on nodes on seam
4254         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
4255         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
4256           const SMDS_MeshNode* nSeam = *noSeIt;
4257           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
4258           if ( n_uv == uvMap.end() )
4259             continue;
4260           // set the first UV
4261           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
4262           // set the second UV
4263           listUV.push_back( *n_uv->second );
4264           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
4265           if ( uvMap2.empty() )
4266             uvMap2 = uvMap; // copy the uvMap contents
4267           uvMap2[ nSeam ] = &listUV.back();
4268
4269           // collect movable nodes linked to ones on seam in nodesNearSeam
4270           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
4271           while ( eIt->more() ) {
4272             const SMDS_MeshElement* e = eIt->next();
4273             int nbUseMap1 = 0, nbUseMap2 = 0;
4274             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
4275             int nn = 0, nbn =  e->NbNodes();
4276             if(e->IsQuadratic()) nbn = nbn/2;
4277             while ( nn++ < nbn )
4278             {
4279               const SMDS_MeshNode* n =
4280                 static_cast<const SMDS_MeshNode*>( nIt->next() );
4281               if (n == nSeam ||
4282                   setMovableNodes.find( n ) == setMovableNodes.end() )
4283                 continue;
4284               // add only nodes being closer to uv2 than to uv1
4285               // gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
4286               //              0.5 * ( n->Y() + nSeam->Y() ),
4287               //              0.5 * ( n->Z() + nSeam->Z() ));
4288               // gp_XY uv;
4289               // getClosestUV( projector, pMid, uv );
4290               double x = uvMap[ n ]->Coord( iPar );
4291               if ( Abs( uv1.Coord( iPar ) - x ) >
4292                    Abs( uv2.Coord( iPar ) - x )) {
4293                 nodesNearSeam.insert( n );
4294                 nbUseMap2++;
4295               }
4296               else
4297                 nbUseMap1++;
4298             }
4299             // for centroidalSmooth all element nodes must
4300             // be on one side of a seam
4301             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
4302               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
4303               nn = 0;
4304               while ( nn++ < nbn ) {
4305                 const SMDS_MeshNode* n =
4306                   static_cast<const SMDS_MeshNode*>( nIt->next() );
4307                 setMovableNodes.erase( n );
4308               }
4309             }
4310           }
4311         } // loop on nodes on seam
4312       } // loop on edge of a face
4313     } // if ( !face.IsNull() )
4314
4315     if ( setMovableNodes.empty() ) {
4316       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
4317       continue; // goto next face
4318     }
4319
4320     // -------------
4321     // SMOOTHING //
4322     // -------------
4323
4324     int it = -1;
4325     double maxRatio = -1., maxDisplacement = -1.;
4326     set<const SMDS_MeshNode*>::iterator nodeToMove;
4327     for ( it = 0; it < theNbIterations; it++ ) {
4328       maxDisplacement = 0.;
4329       nodeToMove = setMovableNodes.begin();
4330       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
4331         const SMDS_MeshNode* node = (*nodeToMove);
4332         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
4333
4334         // smooth
4335         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
4336         if ( theSmoothMethod == LAPLACIAN )
4337           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
4338         else
4339           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
4340
4341         // node displacement
4342         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
4343         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
4344         if ( aDispl > maxDisplacement )
4345           maxDisplacement = aDispl;
4346       }
4347       // no node movement => exit
4348       //if ( maxDisplacement < 1.e-16 ) {
4349       if ( maxDisplacement < disttol ) {
4350         MESSAGE("-- no node movement --");
4351         break;
4352       }
4353
4354       // check elements quality
4355       maxRatio  = 0;
4356       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
4357       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
4358         const SMDS_MeshElement* elem = (*elemIt);
4359         if ( !elem || elem->GetType() != SMDSAbs_Face )
4360           continue;
4361         SMESH::Controls::TSequenceOfXYZ aPoints;
4362         if ( aQualityFunc.GetPoints( elem, aPoints )) {
4363           double aValue = aQualityFunc.GetValue( aPoints );
4364           if ( aValue > maxRatio )
4365             maxRatio = aValue;
4366         }
4367       }
4368       if ( maxRatio <= theTgtAspectRatio ) {
4369         MESSAGE("-- quality achived --");
4370         break;
4371       }
4372       if (it+1 == theNbIterations) {
4373         MESSAGE("-- Iteration limit exceeded --");
4374       }
4375     } // smoothing iterations
4376
4377     MESSAGE(" Face id: " << *fId <<
4378             " Nb iterstions: " << it <<
4379             " Displacement: " << maxDisplacement <<
4380             " Aspect Ratio " << maxRatio);
4381
4382     // ---------------------------------------
4383     // new nodes positions are computed,
4384     // record movement in DS and set new UV
4385     // ---------------------------------------
4386     nodeToMove = setMovableNodes.begin();
4387     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
4388       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
4389       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
4390       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
4391       if ( node_uv != uvMap.end() ) {
4392         gp_XY* uv = node_uv->second;
4393         node->SetPosition
4394           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
4395       }
4396     }
4397
4398     // move medium nodes of quadratic elements
4399     if ( isQuadratic )
4400     {
4401       vector<const SMDS_MeshNode*> nodes;
4402       bool checkUV;
4403       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
4404       for ( ; elemIt != elemsOnFace.end(); ++elemIt )
4405       {
4406         const SMDS_MeshElement* QF = *elemIt;
4407         if ( QF->IsQuadratic() )
4408         {
4409           nodes.assign( SMDS_MeshElement::iterator( QF->interlacedNodesElemIterator() ),
4410                         SMDS_MeshElement::iterator() );
4411           nodes.push_back( nodes[0] );
4412           gp_Pnt xyz;
4413           for (size_t i = 1; i < nodes.size(); i += 2 ) // i points to a medium node
4414           {
4415             if ( !surface.IsNull() )
4416             {
4417               gp_XY uv1 = helper.GetNodeUV( face, nodes[i-1], nodes[i+1], &checkUV );
4418               gp_XY uv2 = helper.GetNodeUV( face, nodes[i+1], nodes[i-1], &checkUV );
4419               gp_XY uv  = helper.GetMiddleUV( surface, uv1, uv2 );
4420               xyz = surface->Value( uv.X(), uv.Y() );
4421             }
4422             else {
4423               xyz = 0.5 * ( SMESH_TNodeXYZ( nodes[i-1] ) + SMESH_TNodeXYZ( nodes[i+1] ));
4424             }
4425             if (( SMESH_TNodeXYZ( nodes[i] ) - xyz.XYZ() ).Modulus() > disttol )
4426               // we have to move a medium node
4427               aMesh->MoveNode( nodes[i], xyz.X(), xyz.Y(), xyz.Z() );
4428           }
4429         }
4430       }
4431     }
4432
4433   } // loop on face ids
4434
4435 }
4436
4437 namespace
4438 {
4439   //=======================================================================
4440   //function : isReverse
4441   //purpose  : Return true if normal of prevNodes is not co-directied with
4442   //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
4443   //           iNotSame is where prevNodes and nextNodes are different.
4444   //           If result is true then future volume orientation is OK
4445   //=======================================================================
4446
4447   bool isReverse(const SMDS_MeshElement*             face,
4448                  const vector<const SMDS_MeshNode*>& prevNodes,
4449                  const vector<const SMDS_MeshNode*>& nextNodes,
4450                  const int                           iNotSame)
4451   {
4452
4453     SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
4454     SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
4455     gp_XYZ extrDir( pN - pP ), faceNorm;
4456     SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false );
4457
4458     return faceNorm * extrDir < 0.0;
4459   }
4460
4461   //================================================================================
4462   /*!
4463    * \brief Assure that theElemSets[0] holds elements, not nodes
4464    */
4465   //================================================================================
4466
4467   void setElemsFirst( TIDSortedElemSet theElemSets[2] )
4468   {
4469     if ( !theElemSets[0].empty() &&
4470          (*theElemSets[0].begin())->GetType() == SMDSAbs_Node )
4471     {
4472       std::swap( theElemSets[0], theElemSets[1] );
4473     }
4474     else if ( !theElemSets[1].empty() &&
4475               (*theElemSets[1].begin())->GetType() != SMDSAbs_Node )
4476     {
4477       std::swap( theElemSets[0], theElemSets[1] );
4478     }
4479   }
4480 }
4481
4482 //=======================================================================
4483 /*!
4484  * \brief Create elements by sweeping an element
4485  * \param elem - element to sweep
4486  * \param newNodesItVec - nodes generated from each node of the element
4487  * \param newElems - generated elements
4488  * \param nbSteps - number of sweeping steps
4489  * \param srcElements - to append elem for each generated element
4490  */
4491 //=======================================================================
4492
4493 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
4494                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
4495                                     list<const SMDS_MeshElement*>&        newElems,
4496                                     const int                             nbSteps,
4497                                     SMESH_SequenceOfElemPtr&              srcElements)
4498 {
4499   //MESSAGE("sweepElement " << nbSteps);
4500   SMESHDS_Mesh* aMesh = GetMeshDS();
4501
4502   const int           nbNodes = elem->NbNodes();
4503   const int         nbCorners = elem->NbCornerNodes();
4504   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of
4505                                                           polyhedron creation !!! */
4506   // Loop on elem nodes:
4507   // find new nodes and detect same nodes indices
4508   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
4509   vector<const SMDS_MeshNode*> prevNod( nbNodes );
4510   vector<const SMDS_MeshNode*> nextNod( nbNodes );
4511   vector<const SMDS_MeshNode*> midlNod( nbNodes );
4512
4513   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
4514   vector<int> sames(nbNodes);
4515   vector<bool> isSingleNode(nbNodes);
4516
4517   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4518     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
4519     const SMDS_MeshNode*                         node = nnIt->first;
4520     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
4521     if ( listNewNodes.empty() )
4522       return;
4523
4524     itNN   [ iNode ] = listNewNodes.begin();
4525     prevNod[ iNode ] = node;
4526     nextNod[ iNode ] = listNewNodes.front();
4527
4528     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
4529                                                              corner node of linear */
4530     if ( prevNod[ iNode ] != nextNod [ iNode ])
4531       nbDouble += !isSingleNode[iNode];
4532
4533     if( iNode < nbCorners ) { // check corners only
4534       if ( prevNod[ iNode ] == nextNod [ iNode ])
4535         sames[nbSame++] = iNode;
4536       else
4537         iNotSameNode = iNode;
4538     }
4539   }
4540
4541   if ( nbSame == nbNodes || nbSame > 2) {
4542     MESSAGE( " Too many same nodes of element " << elem->GetID() );
4543     return;
4544   }
4545
4546   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
4547   {
4548     // fix nodes order to have bottom normal external
4549     if ( baseType == SMDSEntity_Polygon )
4550     {
4551       std::reverse( itNN.begin(), itNN.end() );
4552       std::reverse( prevNod.begin(), prevNod.end() );
4553       std::reverse( midlNod.begin(), midlNod.end() );
4554       std::reverse( nextNod.begin(), nextNod.end() );
4555       std::reverse( isSingleNode.begin(), isSingleNode.end() );
4556     }
4557     else
4558     {
4559       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType, nbNodes );
4560       SMDS_MeshCell::applyInterlace( ind, itNN );
4561       SMDS_MeshCell::applyInterlace( ind, prevNod );
4562       SMDS_MeshCell::applyInterlace( ind, nextNod );
4563       SMDS_MeshCell::applyInterlace( ind, midlNod );
4564       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
4565       if ( nbSame > 0 )
4566       {
4567         sames[nbSame] = iNotSameNode;
4568         for ( int j = 0; j <= nbSame; ++j )
4569           for ( size_t i = 0; i < ind.size(); ++i )
4570             if ( ind[i] == sames[j] )
4571             {
4572               sames[j] = i;
4573               break;
4574             }
4575         iNotSameNode = sames[nbSame];
4576       }
4577     }
4578   }
4579   else if ( elem->GetType() == SMDSAbs_Edge )
4580   {
4581     // orient a new face same as adjacent one
4582     int i1, i2;
4583     const SMDS_MeshElement* e;
4584     TIDSortedElemSet dummy;
4585     if (( e = SMESH_MeshAlgos::FindFaceInSet( nextNod[0], prevNod[0], dummy,dummy, &i1, &i2 )) ||
4586         ( e = SMESH_MeshAlgos::FindFaceInSet( prevNod[1], nextNod[1], dummy,dummy, &i1, &i2 )) ||
4587         ( e = SMESH_MeshAlgos::FindFaceInSet( prevNod[0], prevNod[1], dummy,dummy, &i1, &i2 )))
4588     {
4589       // there is an adjacent face, check order of nodes in it
4590       bool sameOrder = ( Abs( i2 - i1 ) == 1 ) ? ( i2 > i1 ) : ( i2 < i1 );
4591       if ( sameOrder )
4592       {
4593         std::swap( itNN[0],    itNN[1] );
4594         std::swap( prevNod[0], prevNod[1] );
4595         std::swap( nextNod[0], nextNod[1] );
4596         isSingleNode.swap( isSingleNode[0], isSingleNode[1] );
4597         if ( nbSame > 0 )
4598           sames[0] = 1 - sames[0];
4599         iNotSameNode = 1 - iNotSameNode;
4600       }
4601     }
4602   }
4603
4604   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
4605   if ( nbSame > 0 ) {
4606     iSameNode    = sames[ nbSame-1 ];
4607     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
4608     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
4609     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
4610   }
4611
4612   if ( baseType == SMDSEntity_Polygon )
4613   {
4614     if      ( nbNodes == 3 ) baseType = SMDSEntity_Triangle;
4615     else if ( nbNodes == 4 ) baseType = SMDSEntity_Quadrangle;
4616   }
4617   else if ( baseType == SMDSEntity_Quad_Polygon )
4618   {
4619     if      ( nbNodes == 6 ) baseType = SMDSEntity_Quad_Triangle;
4620     else if ( nbNodes == 8 ) baseType = SMDSEntity_Quad_Quadrangle;
4621   }
4622
4623   // make new elements
4624   for (int iStep = 0; iStep < nbSteps; iStep++ )
4625   {
4626     // get next nodes
4627     for ( iNode = 0; iNode < nbNodes; iNode++ )
4628     {
4629       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
4630       nextNod[ iNode ] = *itNN[ iNode ]++;
4631     }
4632
4633     SMDS_MeshElement* aNewElem = 0;
4634     /*if(!elem->IsPoly())*/ {
4635       switch ( baseType ) {
4636       case SMDSEntity_0D:
4637       case SMDSEntity_Node: { // sweep NODE
4638         if ( nbSame == 0 ) {
4639           if ( isSingleNode[0] )
4640             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
4641           else
4642             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
4643         }
4644         else
4645           return;
4646         break;
4647       }
4648       case SMDSEntity_Edge: { // sweep EDGE
4649         if ( nbDouble == 0 )
4650         {
4651           if ( nbSame == 0 ) // ---> quadrangle
4652             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
4653                                       nextNod[ 1 ], nextNod[ 0 ] );
4654           else               // ---> triangle
4655             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
4656                                       nextNod[ iNotSameNode ] );
4657         }
4658         else                 // ---> polygon
4659         {
4660           vector<const SMDS_MeshNode*> poly_nodes;
4661           poly_nodes.push_back( prevNod[0] );
4662           poly_nodes.push_back( prevNod[1] );
4663           if ( prevNod[1] != nextNod[1] )
4664           {
4665             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
4666             poly_nodes.push_back( nextNod[1] );
4667           }
4668           if ( prevNod[0] != nextNod[0] )
4669           {
4670             poly_nodes.push_back( nextNod[0] );
4671             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
4672           }
4673           switch ( poly_nodes.size() ) {
4674           case 3:
4675             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
4676             break;
4677           case 4:
4678             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
4679                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
4680             break;
4681           default:
4682             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
4683           }
4684         }
4685         break;
4686       }
4687       case SMDSEntity_Triangle: // TRIANGLE --->
4688         {
4689           if ( nbDouble > 0 ) break;
4690           if ( nbSame == 0 )       // ---> pentahedron
4691             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
4692                                          nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
4693
4694           else if ( nbSame == 1 )  // ---> pyramid
4695             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
4696                                          nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
4697                                          nextNod[ iSameNode ]);
4698
4699           else // 2 same nodes:       ---> tetrahedron
4700             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
4701                                          nextNod[ iNotSameNode ]);
4702           break;
4703         }
4704       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
4705         {
4706           if ( nbSame == 2 )
4707             return;
4708           if ( nbDouble+nbSame == 2 )
4709           {
4710             if(nbSame==0) {      // ---> quadratic quadrangle
4711               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
4712                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
4713             }
4714             else { //(nbSame==1) // ---> quadratic triangle
4715               if(sames[0]==2) {
4716                 return; // medium node on axis
4717               }
4718               else if(sames[0]==0)
4719                 aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1],
4720                                           prevNod[2], midlNod[1], nextNod[2] );
4721               else // sames[0]==1
4722                 aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[0],
4723                                           prevNod[2], nextNod[2], midlNod[0]);
4724             }
4725           }
4726           else if ( nbDouble == 3 )
4727           {
4728             if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
4729               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
4730                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
4731             }
4732           }
4733           else
4734             return;
4735           break;
4736         }
4737       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
4738         if ( nbDouble > 0 ) break;
4739
4740         if ( nbSame == 0 )       // ---> hexahedron
4741           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
4742                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
4743
4744         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
4745           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
4746                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
4747                                        nextNod[ iSameNode ]);
4748           newElems.push_back( aNewElem );
4749           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
4750                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
4751                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
4752         }
4753         else if ( nbSame == 2 ) { // ---> pentahedron
4754           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
4755             // iBeforeSame is same too
4756             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
4757                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
4758                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
4759           else
4760             // iAfterSame is same too
4761             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
4762                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
4763                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
4764         }
4765         break;
4766       }
4767       case SMDSEntity_Quad_Triangle:  // sweep (Bi)Quadratic TRIANGLE --->
4768       case SMDSEntity_BiQuad_Triangle: /* ??? */ {
4769         if ( nbDouble+nbSame != 3 ) break;
4770         if(nbSame==0) {
4771           // --->  pentahedron with 15 nodes
4772           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
4773                                        nextNod[0], nextNod[1], nextNod[2],
4774                                        prevNod[3], prevNod[4], prevNod[5],
4775                                        nextNod[3], nextNod[4], nextNod[5],
4776                                        midlNod[0], midlNod[1], midlNod[2]);
4777         }
4778         else if(nbSame==1) {
4779           // --->  2d order pyramid of 13 nodes
4780           int apex = iSameNode;
4781           int i0 = ( apex + 1 ) % nbCorners;
4782           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
4783           int i0a = apex + 3;
4784           int i1a = i1 + 3;
4785           int i01 = i0 + 3;
4786           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
4787                                       nextNod[i0], nextNod[i1], prevNod[apex],
4788                                       prevNod[i01], midlNod[i0],
4789                                       nextNod[i01], midlNod[i1],
4790                                       prevNod[i1a], prevNod[i0a],
4791                                       nextNod[i0a], nextNod[i1a]);
4792         }
4793         else if(nbSame==2) {
4794           // --->  2d order tetrahedron of 10 nodes
4795           int n1 = iNotSameNode;
4796           int n2 = ( n1 + 1             ) % nbCorners;
4797           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
4798           int n12 = n1 + 3;
4799           int n23 = n2 + 3;
4800           int n31 = n3 + 3;
4801           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
4802                                        prevNod[n12], prevNod[n23], prevNod[n31],
4803                                        midlNod[n1], nextNod[n12], nextNod[n31]);
4804         }
4805         break;
4806       }
4807       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
4808         if( nbSame == 0 ) {
4809           if ( nbDouble != 4 ) break;
4810           // --->  hexahedron with 20 nodes
4811           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
4812                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
4813                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
4814                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
4815                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
4816         }
4817         else if(nbSame==1) {
4818           // ---> pyramid + pentahedron - can not be created since it is needed
4819           // additional middle node at the center of face
4820           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
4821           return;
4822         }
4823         else if( nbSame == 2 ) {
4824           if ( nbDouble != 2 ) break;
4825           // --->  2d order Pentahedron with 15 nodes
4826           int n1,n2,n4,n5;
4827           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
4828             // iBeforeSame is same too
4829             n1 = iBeforeSame;
4830             n2 = iOpposSame;
4831             n4 = iSameNode;
4832             n5 = iAfterSame;
4833           }
4834           else {
4835             // iAfterSame is same too
4836             n1 = iSameNode;
4837             n2 = iBeforeSame;
4838             n4 = iAfterSame;
4839             n5 = iOpposSame;
4840           }
4841           int n12 = n2 + 4;
4842           int n45 = n4 + 4;
4843           int n14 = n1 + 4;
4844           int n25 = n5 + 4;
4845           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
4846                                        prevNod[n4], prevNod[n5], nextNod[n5],
4847                                        prevNod[n12], midlNod[n2], nextNod[n12],
4848                                        prevNod[n45], midlNod[n5], nextNod[n45],
4849                                        prevNod[n14], prevNod[n25], nextNod[n25]);
4850         }
4851         break;
4852       }
4853       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
4854
4855         if( nbSame == 0 && nbDouble == 9 ) {
4856           // --->  tri-quadratic hexahedron with 27 nodes
4857           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
4858                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
4859                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
4860                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
4861                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
4862                                        prevNod[8], // bottom center
4863                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
4864                                        nextNod[8], // top center
4865                                        midlNod[8]);// elem center
4866         }
4867         else
4868         {
4869           return;
4870         }
4871         break;
4872       }
4873       case SMDSEntity_Polygon: { // sweep POLYGON
4874
4875         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
4876           // --->  hexagonal prism
4877           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
4878                                        prevNod[3], prevNod[4], prevNod[5],
4879                                        nextNod[0], nextNod[1], nextNod[2],
4880                                        nextNod[3], nextNod[4], nextNod[5]);
4881         }
4882         break;
4883       }
4884       case SMDSEntity_Ball:
4885         return;
4886
4887       default:
4888         break;
4889       } // switch ( baseType )
4890     } // scope
4891
4892     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
4893     {
4894       if ( baseType != SMDSEntity_Polygon )
4895       {
4896         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType,nbNodes);
4897         SMDS_MeshCell::applyInterlace( ind, prevNod );
4898         SMDS_MeshCell::applyInterlace( ind, nextNod );
4899         SMDS_MeshCell::applyInterlace( ind, midlNod );
4900         SMDS_MeshCell::applyInterlace( ind, itNN );
4901         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
4902         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
4903       }
4904       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
4905       vector<int> quantities (nbNodes + 2);
4906       polyedre_nodes.clear();
4907       quantities.clear();
4908
4909       // bottom of prism
4910       for (int inode = 0; inode < nbNodes; inode++)
4911         polyedre_nodes.push_back( prevNod[inode] );
4912       quantities.push_back( nbNodes );
4913
4914       // top of prism
4915       polyedre_nodes.push_back( nextNod[0] );
4916       for (int inode = nbNodes; inode-1; --inode )
4917         polyedre_nodes.push_back( nextNod[inode-1] );
4918       quantities.push_back( nbNodes );
4919
4920       // side faces
4921       // 3--6--2
4922       // |     |
4923       // 7     5
4924       // |     |
4925       // 0--4--1
4926       const int iQuad = elem->IsQuadratic();
4927       for (int iface = 0; iface < nbNodes; iface += 1+iQuad )
4928       {
4929         const int prevNbNodes = polyedre_nodes.size(); // to detect degenerated face
4930         int inextface = (iface+1+iQuad) % nbNodes;
4931         int imid      = (iface+1) % nbNodes;
4932         polyedre_nodes.push_back( prevNod[inextface] );         // 0
4933         if ( iQuad ) polyedre_nodes.push_back( prevNod[imid] ); // 4
4934         polyedre_nodes.push_back( prevNod[iface] );             // 1
4935         if ( prevNod[iface] != nextNod[iface] ) // 1 != 2
4936         {
4937           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]); // 5
4938           polyedre_nodes.push_back( nextNod[iface] );                         // 2
4939         }
4940         if ( iQuad ) polyedre_nodes.push_back( nextNod[imid] );               // 6
4941         if ( prevNod[inextface] != nextNod[inextface] ) // 0 != 3
4942         {
4943           polyedre_nodes.push_back( nextNod[inextface] );                            // 3
4944           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);// 7
4945         }
4946         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
4947         if ( nbFaceNodes > 2 )
4948           quantities.push_back( nbFaceNodes );
4949         else // degenerated face
4950           polyedre_nodes.resize( prevNbNodes );
4951       }
4952       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
4953
4954     } // try to create a polyherdal prism
4955
4956     if ( aNewElem ) {
4957       newElems.push_back( aNewElem );
4958       myLastCreatedElems.Append(aNewElem);
4959       srcElements.Append( elem );
4960     }
4961
4962     // set new prev nodes
4963     for ( iNode = 0; iNode < nbNodes; iNode++ )
4964       prevNod[ iNode ] = nextNod[ iNode ];
4965
4966   } // loop on steps
4967 }
4968
4969 //=======================================================================
4970 /*!
4971  * \brief Create 1D and 2D elements around swept elements
4972  * \param mapNewNodes - source nodes and ones generated from them
4973  * \param newElemsMap - source elements and ones generated from them
4974  * \param elemNewNodesMap - nodes generated from each node of each element
4975  * \param elemSet - all swept elements
4976  * \param nbSteps - number of sweeping steps
4977  * \param srcElements - to append elem for each generated element
4978  */
4979 //=======================================================================
4980
4981 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
4982                                   TTElemOfElemListMap &    newElemsMap,
4983                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
4984                                   TIDSortedElemSet&        elemSet,
4985                                   const int                nbSteps,
4986                                   SMESH_SequenceOfElemPtr& srcElements)
4987 {
4988   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
4989   SMESHDS_Mesh* aMesh = GetMeshDS();
4990
4991   // Find nodes belonging to only one initial element - sweep them into edges.
4992
4993   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
4994   for ( ; nList != mapNewNodes.end(); nList++ )
4995   {
4996     const SMDS_MeshNode* node =
4997       static_cast<const SMDS_MeshNode*>( nList->first );
4998     if ( newElemsMap.count( node ))
4999       continue; // node was extruded into edge
5000     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
5001     int nbInitElems = 0;
5002     const SMDS_MeshElement* el = 0;
5003     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
5004     while ( eIt->more() && nbInitElems < 2 ) {
5005       const SMDS_MeshElement* e = eIt->next();
5006       SMDSAbs_ElementType type = e->GetType();
5007       if ( type == SMDSAbs_Volume || type < highType ) continue;
5008       if ( type > highType ) {
5009         nbInitElems = 0;
5010         highType = type;
5011       }
5012       el = e;
5013       nbInitElems += elemSet.count(el);
5014     }
5015     if ( nbInitElems < 2 ) {
5016       bool NotCreateEdge = el && el->IsMediumNode(node);
5017       if(!NotCreateEdge) {
5018         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
5019         list<const SMDS_MeshElement*> newEdges;
5020         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
5021       }
5022     }
5023   }
5024
5025   // Make a ceiling for each element ie an equal element of last new nodes.
5026   // Find free links of faces - make edges and sweep them into faces.
5027
5028   ElemFeatures polyFace( SMDSAbs_Face, /*isPoly=*/true ), anyFace;
5029
5030   TTElemOfElemListMap::iterator  itElem      = newElemsMap.begin();
5031   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
5032   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
5033   {
5034     const SMDS_MeshElement* elem = itElem->first;
5035     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
5036
5037     if(itElem->second.size()==0) continue;
5038
5039     const bool isQuadratic = elem->IsQuadratic();
5040
5041     if ( elem->GetType() == SMDSAbs_Edge ) {
5042       // create a ceiling edge
5043       if ( !isQuadratic ) {
5044         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
5045                                vecNewNodes[ 1 ]->second.back())) {
5046           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
5047                                                    vecNewNodes[ 1 ]->second.back()));
5048           srcElements.Append( elem );
5049         }
5050       }
5051       else {
5052         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
5053                                vecNewNodes[ 1 ]->second.back(),
5054                                vecNewNodes[ 2 ]->second.back())) {
5055           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
5056                                                    vecNewNodes[ 1 ]->second.back(),
5057                                                    vecNewNodes[ 2 ]->second.back()));
5058           srcElements.Append( elem );
5059         }
5060       }
5061     }
5062     if ( elem->GetType() != SMDSAbs_Face )
5063       continue;
5064
5065     bool hasFreeLinks = false;
5066
5067     TIDSortedElemSet avoidSet;
5068     avoidSet.insert( elem );
5069
5070     set<const SMDS_MeshNode*> aFaceLastNodes;
5071     int iNode, nbNodes = vecNewNodes.size();
5072     if ( !isQuadratic ) {
5073       // loop on the face nodes
5074       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
5075         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
5076         // look for free links of the face
5077         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
5078         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
5079         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
5080         // check if a link n1-n2 is free
5081         if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
5082           hasFreeLinks = true;
5083           // make a new edge and a ceiling for a new edge
5084           const SMDS_MeshElement* edge;
5085           if ( ! ( edge = aMesh->FindEdge( n1, n2 ))) {
5086             myLastCreatedElems.Append( edge = aMesh->AddEdge( n1, n2 )); // free link edge
5087             srcElements.Append( myLastCreatedElems.Last() );
5088           }
5089           n1 = vecNewNodes[ iNode ]->second.back();
5090           n2 = vecNewNodes[ iNext ]->second.back();
5091           if ( !aMesh->FindEdge( n1, n2 )) {
5092             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling
5093             srcElements.Append( edge );
5094           }
5095         }
5096       }
5097     }
5098     else { // elem is quadratic face
5099       int nbn = nbNodes/2;
5100       for ( iNode = 0; iNode < nbn; iNode++ ) {
5101         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
5102         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
5103         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
5104         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
5105         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
5106         // check if a link is free
5107         if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
5108              ! SMESH_MeshAlgos::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
5109              ! SMESH_MeshAlgos::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
5110           hasFreeLinks = true;
5111           // make an edge and a ceiling for a new edge
5112           // find medium node
5113           if ( !aMesh->FindEdge( n1, n2, n3 )) {
5114             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
5115             srcElements.Append( elem );
5116           }
5117           n1 = vecNewNodes[ iNode ]->second.back();
5118           n2 = vecNewNodes[ iNext ]->second.back();
5119           n3 = vecNewNodes[ iNode+nbn ]->second.back();
5120           if ( !aMesh->FindEdge( n1, n2, n3 )) {
5121             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
5122             srcElements.Append( elem );
5123           }
5124         }
5125       }
5126       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
5127         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
5128       }
5129     }
5130
5131     // sweep free links into faces
5132
5133     if ( hasFreeLinks ) {
5134       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
5135       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
5136
5137       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
5138       set<const SMDS_MeshNode*> initNodeSetNoCenter/*, topNodeSetNoCenter*/;
5139       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
5140         initNodeSet.insert( vecNewNodes[ iNode ]->first );
5141         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
5142       }
5143       if ( isQuadratic && nbNodes % 2 ) {  // node set for the case of a biquadratic
5144         initNodeSetNoCenter = initNodeSet; // swept face and a not biquadratic volume
5145         initNodeSetNoCenter.erase( vecNewNodes.back()->first );
5146       }
5147       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
5148         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
5149         std::advance( v, volNb );
5150         // find indices of free faces of a volume and their source edges
5151         list< int > freeInd;
5152         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
5153         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
5154         int iF, nbF = vTool.NbFaces();
5155         for ( iF = 0; iF < nbF; iF ++ ) {
5156           if (vTool.IsFreeFace( iF ) &&
5157               vTool.GetFaceNodes( iF, faceNodeSet ) &&
5158               initNodeSet != faceNodeSet) // except an initial face
5159           {
5160             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
5161               continue;
5162             if ( faceNodeSet == initNodeSetNoCenter )
5163               continue;
5164             freeInd.push_back( iF );
5165             // find source edge of a free face iF
5166             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
5167             vector<const SMDS_MeshNode*>::iterator lastCommom;
5168             commonNodes.resize( nbNodes, 0 );
5169             lastCommom = std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
5170                                                 initNodeSet.begin(), initNodeSet.end(),
5171                                                 commonNodes.begin());
5172             if ( std::distance( commonNodes.begin(), lastCommom ) == 3 )
5173               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
5174             else
5175               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
5176 #ifdef _DEBUG_
5177             if ( !srcEdges.back() )
5178             {
5179               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
5180                    << iF << " of volume #" << vTool.ID() << endl;
5181             }
5182 #endif
5183           }
5184         }
5185         if ( freeInd.empty() )
5186           continue;
5187
5188         // create wall faces for all steps;
5189         // if such a face has been already created by sweep of edge,
5190         // assure that its orientation is OK
5191         for ( int iStep = 0; iStep < nbSteps; iStep++ )
5192         {
5193           vTool.Set( *v, /*ignoreCentralNodes=*/false );
5194           vTool.SetExternalNormal();
5195           const int nextShift = vTool.IsForward() ? +1 : -1;
5196           list< int >::iterator ind = freeInd.begin();
5197           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
5198           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
5199           {
5200             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
5201             int nbn = vTool.NbFaceNodes( *ind );
5202             const SMDS_MeshElement * f = 0;
5203             if ( nbn == 3 )              ///// triangle
5204             {
5205               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
5206               if ( !f ||
5207                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
5208               {
5209                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
5210                                                      nodes[ 1 ],
5211                                                      nodes[ 1 + nextShift ] };
5212                 if ( f )
5213                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
5214                 else
5215                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
5216                                                             newOrder[ 2 ] ));
5217               }
5218             }
5219             else if ( nbn == 4 )       ///// quadrangle
5220             {
5221               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
5222               if ( !f ||
5223                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
5224               {
5225                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
5226                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
5227                 if ( f )
5228                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
5229                 else
5230                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
5231                                                             newOrder[ 2 ], newOrder[ 3 ]));
5232               }
5233             }
5234             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
5235             {
5236               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
5237               if ( !f ||
5238                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
5239               {
5240                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
5241                                                      nodes[2],
5242                                                      nodes[2 + 2*nextShift],
5243                                                      nodes[3 - 2*nextShift],
5244                                                      nodes[3],
5245                                                      nodes[3 + 2*nextShift]};
5246                 if ( f )
5247                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
5248                 else
5249                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
5250                                                             newOrder[ 1 ],
5251                                                             newOrder[ 2 ],
5252                                                             newOrder[ 3 ],
5253                                                             newOrder[ 4 ],
5254                                                             newOrder[ 5 ] ));
5255               }
5256             }
5257             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
5258             {
5259               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
5260                                    nodes[1], nodes[3], nodes[5], nodes[7] );
5261               if ( !f ||
5262                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
5263               {
5264                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
5265                                                      nodes[4 - 2*nextShift],
5266                                                      nodes[4],
5267                                                      nodes[4 + 2*nextShift],
5268                                                      nodes[1],
5269                                                      nodes[5 - 2*nextShift],
5270                                                      nodes[5],
5271                                                      nodes[5 + 2*nextShift] };
5272                 if ( f )
5273                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
5274                 else
5275                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
5276                                                            newOrder[ 2 ], newOrder[ 3 ],
5277                                                            newOrder[ 4 ], newOrder[ 5 ],
5278                                                            newOrder[ 6 ], newOrder[ 7 ]));
5279               }
5280             }
5281             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
5282             {
5283               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
5284                                       SMDSAbs_Face, /*noMedium=*/false);
5285               if ( !f ||
5286                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
5287               {
5288                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
5289                                                      nodes[4 - 2*nextShift],
5290                                                      nodes[4],
5291                                                      nodes[4 + 2*nextShift],
5292                                                      nodes[1],
5293                                                      nodes[5 - 2*nextShift],
5294                                                      nodes[5],
5295                                                      nodes[5 + 2*nextShift],
5296                                                      nodes[8] };
5297                 if ( f )
5298                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
5299                 else
5300                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
5301                                                            newOrder[ 2 ], newOrder[ 3 ],
5302                                                            newOrder[ 4 ], newOrder[ 5 ],
5303                                                            newOrder[ 6 ], newOrder[ 7 ],
5304                                                            newOrder[ 8 ]));
5305               }
5306             }
5307             else  //////// polygon
5308             {
5309               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
5310               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
5311               if ( !f ||
5312                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
5313               {
5314                 if ( !vTool.IsForward() )
5315                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
5316                 if ( f )
5317                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
5318                 else
5319                   AddElement( polygon_nodes, polyFace.SetQuad( (*v)->IsQuadratic() ));
5320               }
5321             }
5322
5323             while ( srcElements.Length() < myLastCreatedElems.Length() )
5324               srcElements.Append( *srcEdge );
5325
5326           }  // loop on free faces
5327
5328           // go to the next volume
5329           iVol = 0;
5330           while ( iVol++ < nbVolumesByStep ) v++;
5331
5332         } // loop on steps
5333       } // loop on volumes of one step
5334     } // sweep free links into faces
5335
5336     // Make a ceiling face with a normal external to a volume
5337
5338     // use SMDS_VolumeTool to get a correctly ordered nodes of a ceiling face
5339     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
5340     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
5341
5342     if ( iF < 0 && isQuadratic && nbNodes % 2 ) { // remove a central node of biquadratic
5343       aFaceLastNodes.erase( vecNewNodes.back()->second.back() );
5344       iF = lastVol.GetFaceIndex( aFaceLastNodes );
5345     }
5346     if ( iF >= 0 )
5347     {
5348       lastVol.SetExternalNormal();
5349       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
5350       const               int nbn = lastVol.NbFaceNodes( iF );
5351       vector<const SMDS_MeshNode*> nodeVec( nodes, nodes+nbn );
5352       if ( !hasFreeLinks ||
5353            !aMesh->FindElement( nodeVec, SMDSAbs_Face, /*noMedium=*/false) )
5354       {
5355         const vector<int>& interlace =
5356           SMDS_MeshCell::interlacedSmdsOrder( elem->GetEntityType(), nbn );
5357         SMDS_MeshCell::applyInterlaceRev( interlace, nodeVec );
5358
5359         if ( const SMDS_MeshElement* face = AddElement( nodeVec, anyFace.Init( elem )))
5360           myLastCreatedElems.Append( face );
5361
5362         while ( srcElements.Length() < myLastCreatedElems.Length() )
5363           srcElements.Append( elem );
5364       }
5365     }
5366   } // loop on swept elements
5367 }
5368
5369 //=======================================================================
5370 //function : RotationSweep
5371 //purpose  :
5372 //=======================================================================
5373
5374 SMESH_MeshEditor::PGroupIDs
5375 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet   theElemSets[2],
5376                                 const gp_Ax1&      theAxis,
5377                                 const double       theAngle,
5378                                 const int          theNbSteps,
5379                                 const double       theTol,
5380                                 const bool         theMakeGroups,
5381                                 const bool         theMakeWalls)
5382 {
5383   myLastCreatedElems.Clear();
5384   myLastCreatedNodes.Clear();
5385
5386   // source elements for each generated one
5387   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5388
5389   MESSAGE( "RotationSweep()");
5390   gp_Trsf aTrsf;
5391   aTrsf.SetRotation( theAxis, theAngle );
5392   gp_Trsf aTrsf2;
5393   aTrsf2.SetRotation( theAxis, theAngle/2. );
5394
5395   gp_Lin aLine( theAxis );
5396   double aSqTol = theTol * theTol;
5397
5398   SMESHDS_Mesh* aMesh = GetMeshDS();
5399
5400   TNodeOfNodeListMap mapNewNodes;
5401   TElemOfVecOfNnlmiMap mapElemNewNodes;
5402   TTElemOfElemListMap newElemsMap;
5403
5404   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
5405                                      myMesh->NbFaces(ORDER_QUADRATIC) +
5406                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
5407   // loop on theElemSets
5408   setElemsFirst( theElemSets );
5409   TIDSortedElemSet::iterator itElem;
5410   for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
5411   {
5412     TIDSortedElemSet& theElems = theElemSets[ is2ndSet ];
5413     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5414       const SMDS_MeshElement* elem = *itElem;
5415       if ( !elem || elem->GetType() == SMDSAbs_Volume )
5416         continue;
5417       vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5418       newNodesItVec.reserve( elem->NbNodes() );
5419
5420       // loop on elem nodes
5421       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5422       while ( itN->more() )
5423       {
5424         const SMDS_MeshNode* node = cast2Node( itN->next() );
5425
5426         gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
5427         double coord[3];
5428         aXYZ.Coord( coord[0], coord[1], coord[2] );
5429         bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
5430
5431         // check if a node has been already sweeped
5432         TNodeOfNodeListMapItr nIt =
5433           mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5434         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5435         if ( listNewNodes.empty() )
5436         {
5437           // check if we are to create medium nodes between corner ones
5438           bool needMediumNodes = false;
5439           if ( isQuadraticMesh )
5440           {
5441             SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
5442             while (it->more() && !needMediumNodes )
5443             {
5444               const SMDS_MeshElement* invElem = it->next();
5445               if ( invElem != elem && !theElems.count( invElem )) continue;
5446               needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
5447               if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
5448                 needMediumNodes = true;
5449             }
5450           }
5451
5452           // make new nodes
5453           const SMDS_MeshNode * newNode = node;
5454           for ( int i = 0; i < theNbSteps; i++ ) {
5455             if ( !isOnAxis ) {
5456               if ( needMediumNodes )  // create a medium node
5457               {
5458                 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
5459                 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5460                 myLastCreatedNodes.Append(newNode);
5461                 srcNodes.Append( node );
5462                 listNewNodes.push_back( newNode );
5463                 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
5464               }
5465               else {
5466                 aTrsf.Transforms( coord[0], coord[1], coord[2] );
5467               }
5468               // create a corner node
5469               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5470               myLastCreatedNodes.Append(newNode);
5471               srcNodes.Append( node );
5472               listNewNodes.push_back( newNode );
5473             }
5474             else {
5475               listNewNodes.push_back( newNode );
5476               // if ( needMediumNodes )
5477               //   listNewNodes.push_back( newNode );
5478             }
5479           }
5480         }
5481         newNodesItVec.push_back( nIt );
5482       }
5483       // make new elements
5484       sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
5485     }
5486   }
5487
5488   if ( theMakeWalls )
5489     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], theNbSteps, srcElems );
5490
5491   PGroupIDs newGroupIDs;
5492   if ( theMakeGroups )
5493     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
5494
5495   return newGroupIDs;
5496 }
5497
5498 //=======================================================================
5499 //function : ExtrusParam
5500 //purpose  : standard construction
5501 //=======================================================================
5502
5503 SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Vec&  theStep,
5504                                             const int      theNbSteps,
5505                                             const int      theFlags,
5506                                             const double   theTolerance):
5507   myDir( theStep ),
5508   myFlags( theFlags ),
5509   myTolerance( theTolerance ),
5510   myElemsToUse( NULL )
5511 {
5512   mySteps = new TColStd_HSequenceOfReal;
5513   const double stepSize = theStep.Magnitude();
5514   for (int i=1; i<=theNbSteps; i++ )
5515     mySteps->Append( stepSize );
5516
5517   if (( theFlags & EXTRUSION_FLAG_SEW ) &&
5518       ( theTolerance > 0 ))
5519   {
5520     myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDirAndSew;
5521   }
5522   else
5523   {
5524     myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDir;
5525   }
5526 }
5527
5528 //=======================================================================
5529 //function : ExtrusParam
5530 //purpose  : steps are given explicitly
5531 //=======================================================================
5532
5533 SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Dir&                   theDir,
5534                                             Handle(TColStd_HSequenceOfReal) theSteps,
5535                                             const int                       theFlags,
5536                                             const double                    theTolerance):
5537   myDir( theDir ),
5538   mySteps( theSteps ),
5539   myFlags( theFlags ),
5540   myTolerance( theTolerance ),
5541   myElemsToUse( NULL )
5542 {
5543   if (( theFlags & EXTRUSION_FLAG_SEW ) &&
5544       ( theTolerance > 0 ))
5545   {
5546     myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDirAndSew;
5547   }
5548   else
5549   {
5550     myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDir;
5551   }
5552 }
5553
5554 //=======================================================================
5555 //function : ExtrusParam
5556 //purpose  : for extrusion by normal
5557 //=======================================================================
5558
5559 SMESH_MeshEditor::ExtrusParam::ExtrusParam( const double theStepSize,
5560                                             const int    theNbSteps,
5561                                             const int    theFlags,
5562                                             const int    theDim ):
5563   myDir( 1,0,0 ),
5564   mySteps( new TColStd_HSequenceOfReal ),
5565   myFlags( theFlags ),
5566   myTolerance( 0 ),
5567   myElemsToUse( NULL )
5568 {
5569   for (int i = 0; i < theNbSteps; i++ )
5570     mySteps->Append( theStepSize );
5571
5572   if ( theDim == 1 )
5573   {
5574     myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByNormal1D;
5575   }
5576   else
5577   {
5578     myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByNormal2D;
5579   }
5580 }
5581
5582 //=======================================================================
5583 //function : ExtrusParam::SetElementsToUse
5584 //purpose  : stores elements to use for extrusion by normal, depending on
5585 //           state of EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY flag
5586 //=======================================================================
5587
5588 void SMESH_MeshEditor::ExtrusParam::SetElementsToUse( const TIDSortedElemSet& elems )
5589 {
5590   myElemsToUse = ToUseInpElemsOnly() ? & elems : 0;
5591 }
5592
5593 //=======================================================================
5594 //function : ExtrusParam::beginStepIter
5595 //purpose  : prepare iteration on steps
5596 //=======================================================================
5597
5598 void SMESH_MeshEditor::ExtrusParam::beginStepIter( bool withMediumNodes )
5599 {
5600   myWithMediumNodes = withMediumNodes;
5601   myNextStep = 1;
5602   myCurSteps.clear();
5603 }
5604 //=======================================================================
5605 //function : ExtrusParam::moreSteps
5606 //purpose  : are there more steps?
5607 //=======================================================================
5608
5609 bool SMESH_MeshEditor::ExtrusParam::moreSteps()
5610 {
5611   return myNextStep <= mySteps->Length() || !myCurSteps.empty();
5612 }
5613 //=======================================================================
5614 //function : ExtrusParam::nextStep
5615 //purpose  : returns the next step
5616 //=======================================================================
5617
5618 double SMESH_MeshEditor::ExtrusParam::nextStep()
5619 {
5620   double res = 0;
5621   if ( !myCurSteps.empty() )
5622   {
5623     res = myCurSteps.back();
5624     myCurSteps.pop_back();
5625   }
5626   else if ( myNextStep <= mySteps->Length() )
5627   {
5628     myCurSteps.push_back( mySteps->Value( myNextStep ));
5629     ++myNextStep;
5630     if ( myWithMediumNodes )
5631     {
5632       myCurSteps.back() /= 2.;
5633       myCurSteps.push_back( myCurSteps.back() );
5634     }
5635     res = nextStep();
5636   }
5637   return res;
5638 }
5639
5640 //=======================================================================
5641 //function : ExtrusParam::makeNodesByDir
5642 //purpose  : create nodes for standard extrusion
5643 //=======================================================================
5644
5645 int SMESH_MeshEditor::ExtrusParam::
5646 makeNodesByDir( SMESHDS_Mesh*                     mesh,
5647                 const SMDS_MeshNode*              srcNode,
5648                 std::list<const SMDS_MeshNode*> & newNodes,
5649                 const bool                        makeMediumNodes)
5650 {
5651   gp_XYZ p = SMESH_TNodeXYZ( srcNode );
5652
5653   int nbNodes = 0;
5654   for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps
5655   {
5656     p += myDir.XYZ() * nextStep();
5657     const SMDS_MeshNode * newNode = mesh->AddNode( p.X(), p.Y(), p.Z() );
5658     newNodes.push_back( newNode );
5659   }
5660   return nbNodes;
5661 }
5662
5663 //=======================================================================
5664 //function : ExtrusParam::makeNodesByDirAndSew
5665 //purpose  : create nodes for standard extrusion with sewing
5666 //=======================================================================
5667
5668 int SMESH_MeshEditor::ExtrusParam::
5669 makeNodesByDirAndSew( SMESHDS_Mesh*                     mesh,
5670                       const SMDS_MeshNode*              srcNode,
5671                       std::list<const SMDS_MeshNode*> & newNodes,
5672                       const bool                        makeMediumNodes)
5673 {
5674   gp_XYZ P1 = SMESH_TNodeXYZ( srcNode );
5675
5676   int nbNodes = 0;
5677   for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps
5678   {
5679     P1 += myDir.XYZ() * nextStep();
5680
5681     // try to search in sequence of existing nodes
5682     // if myNodes.Length()>0 we 'nave to use given sequence
5683     // else - use all nodes of mesh
5684     const SMDS_MeshNode * node = 0;
5685     if ( myNodes.Length() > 0 ) {
5686       int i;
5687       for(i=1; i<=myNodes.Length(); i++) {
5688         gp_XYZ P2 = SMESH_TNodeXYZ( myNodes.Value(i) );
5689         if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance )
5690         {
5691           node = myNodes.Value(i);
5692           break;
5693         }
5694       }
5695     }
5696     else {
5697       SMDS_NodeIteratorPtr itn = mesh->nodesIterator();
5698       while(itn->more()) {
5699         SMESH_TNodeXYZ P2( itn->next() );
5700         if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance )
5701         {
5702           node = P2._node;
5703           break;
5704         }
5705       }
5706     }
5707
5708     if ( !node )
5709       node = mesh->AddNode( P1.X(), P1.Y(), P1.Z() );
5710
5711     newNodes.push_back( node );
5712
5713   } // loop on steps
5714
5715   return nbNodes;
5716 }
5717
5718 //=======================================================================
5719 //function : ExtrusParam::makeNodesByNormal2D
5720 //purpose  : create nodes for extrusion using normals of faces
5721 //=======================================================================
5722
5723 int SMESH_MeshEditor::ExtrusParam::
5724 makeNodesByNormal2D( SMESHDS_Mesh*                     mesh,
5725                      const SMDS_MeshNode*              srcNode,
5726                      std::list<const SMDS_MeshNode*> & newNodes,
5727                      const bool                        makeMediumNodes)
5728 {
5729   const bool alongAvgNorm = ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL );
5730
5731   gp_XYZ p = SMESH_TNodeXYZ( srcNode );
5732
5733   // get normals to faces sharing srcNode
5734   vector< gp_XYZ > norms, baryCenters;
5735   gp_XYZ norm, avgNorm( 0,0,0 );
5736   SMDS_ElemIteratorPtr faceIt = srcNode->GetInverseElementIterator( SMDSAbs_Face );
5737   while ( faceIt->more() )
5738   {
5739     const SMDS_MeshElement* face = faceIt->next();
5740     if ( myElemsToUse && !myElemsToUse->count( face ))
5741       continue;
5742     if ( SMESH_MeshAlgos::FaceNormal( face, norm, /*normalized=*/true ))
5743     {
5744       norms.push_back( norm );
5745       avgNorm += norm;
5746       if ( !alongAvgNorm )
5747       {
5748         gp_XYZ bc(0,0,0);
5749         int nbN = 0;
5750         for ( SMDS_ElemIteratorPtr nIt = face->nodesIterator(); nIt->more(); ++nbN )
5751           bc += SMESH_TNodeXYZ( nIt->next() );
5752         baryCenters.push_back( bc / nbN );
5753       }
5754     }
5755   }
5756
5757   if ( norms.empty() ) return 0;
5758
5759   double normSize = avgNorm.Modulus();
5760   if ( normSize < std::numeric_limits<double>::min() )
5761     return 0;
5762
5763   if ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL ) // extrude along avgNorm
5764   {
5765     myDir = avgNorm;
5766     return makeNodesByDir( mesh, srcNode, newNodes, makeMediumNodes );
5767   }
5768
5769   avgNorm /= normSize;
5770
5771   int nbNodes = 0;
5772   for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps
5773   {
5774     gp_XYZ pNew = p;
5775     double stepSize = nextStep();
5776
5777     if ( norms.size() > 1 )
5778     {
5779       for ( size_t iF = 0; iF < norms.size(); ++iF ) // loop on faces
5780       {
5781         // translate plane of a face
5782         baryCenters[ iF ] += norms[ iF ] * stepSize;
5783
5784         // find point of intersection of the face plane located at baryCenters[ iF ]
5785         // and avgNorm located at pNew
5786         double d    = -( norms[ iF ] * baryCenters[ iF ]); // d of plane equation ax+by+cz+d=0
5787         double dot  = ( norms[ iF ] * avgNorm );
5788         if ( dot < std::numeric_limits<double>::min() )
5789           dot = stepSize * 1e-3;
5790         double step = -( norms[ iF ] * pNew + d ) / dot;
5791         pNew += step * avgNorm;
5792       }
5793     }
5794     else
5795     {
5796       pNew += stepSize * avgNorm;
5797     }
5798     p = pNew;
5799
5800     const SMDS_MeshNode * newNode = mesh->AddNode( p.X(), p.Y(), p.Z() );
5801     newNodes.push_back( newNode );
5802   }
5803   return nbNodes;
5804 }
5805
5806 //=======================================================================
5807 //function : ExtrusParam::makeNodesByNormal1D
5808 //purpose  : create nodes for extrusion using normals of edges
5809 //=======================================================================
5810
5811 int SMESH_MeshEditor::ExtrusParam::
5812 makeNodesByNormal1D( SMESHDS_Mesh*                     mesh,
5813                      const SMDS_MeshNode*              srcNode,
5814                      std::list<const SMDS_MeshNode*> & newNodes,
5815                      const bool                        makeMediumNodes)
5816 {
5817   throw SALOME_Exception("Extrusion 1D by Normal not implemented");
5818   return 0;
5819 }
5820
5821 //=======================================================================
5822 //function : ExtrusionSweep
5823 //purpose  :
5824 //=======================================================================
5825
5826 SMESH_MeshEditor::PGroupIDs
5827 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet     theElems[2],
5828                                   const gp_Vec&        theStep,
5829                                   const int            theNbSteps,
5830                                   TTElemOfElemListMap& newElemsMap,
5831                                   const int            theFlags,
5832                                   const double         theTolerance)
5833 {
5834   ExtrusParam aParams( theStep, theNbSteps, theFlags, theTolerance );
5835   return ExtrusionSweep( theElems, aParams, newElemsMap );
5836 }
5837
5838
5839 //=======================================================================
5840 //function : ExtrusionSweep
5841 //purpose  :
5842 //=======================================================================
5843
5844 SMESH_MeshEditor::PGroupIDs
5845 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet     theElemSets[2],
5846                                   ExtrusParam&         theParams,
5847                                   TTElemOfElemListMap& newElemsMap)
5848 {
5849   myLastCreatedElems.Clear();
5850   myLastCreatedNodes.Clear();
5851
5852   // source elements for each generated one
5853   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5854
5855   SMESHDS_Mesh* aMesh = GetMeshDS();
5856
5857   setElemsFirst( theElemSets );
5858   const int nbSteps = theParams.NbSteps();
5859   theParams.SetElementsToUse( theElemSets[0] );
5860
5861   TNodeOfNodeListMap mapNewNodes;
5862   //TNodeOfNodeVecMap mapNewNodes;
5863   TElemOfVecOfNnlmiMap mapElemNewNodes;
5864   //TElemOfVecOfMapNodesMap mapElemNewNodes;
5865
5866   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
5867                                      myMesh->NbFaces(ORDER_QUADRATIC) +
5868                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
5869   // loop on theElems
5870   TIDSortedElemSet::iterator itElem;
5871   for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
5872   {
5873     TIDSortedElemSet& theElems = theElemSets[ is2ndSet ];
5874     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5875     {
5876       // check element type
5877       const SMDS_MeshElement* elem = *itElem;
5878       if ( !elem  || elem->GetType() == SMDSAbs_Volume )
5879         continue;
5880
5881       const size_t nbNodes = elem->NbNodes();
5882       vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5883       newNodesItVec.reserve( nbNodes );
5884
5885       // loop on elem nodes
5886       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5887       while ( itN->more() )
5888       {
5889         // check if a node has been already sweeped
5890         const SMDS_MeshNode* node = cast2Node( itN->next() );
5891         TNodeOfNodeListMap::iterator nIt =
5892           mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5893         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5894         if ( listNewNodes.empty() )
5895         {
5896           // make new nodes
5897
5898           // check if we are to create medium nodes between corner ones
5899           bool needMediumNodes = false;
5900           if ( isQuadraticMesh )
5901           {
5902             SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
5903             while (it->more() && !needMediumNodes )
5904             {
5905               const SMDS_MeshElement* invElem = it->next();
5906               if ( invElem != elem && !theElems.count( invElem )) continue;
5907               needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
5908               if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
5909                 needMediumNodes = true;
5910             }
5911           }
5912           // create nodes for all steps
5913           if ( theParams.MakeNodes( GetMeshDS(), node, listNewNodes, needMediumNodes ))
5914           {
5915             list<const SMDS_MeshNode*>::iterator newNodesIt = listNewNodes.begin();
5916             for ( ; newNodesIt != listNewNodes.end(); ++newNodesIt )
5917             {
5918               myLastCreatedNodes.Append( *newNodesIt );
5919               srcNodes.Append( node );
5920             }
5921           }
5922           else
5923           {
5924             break; // newNodesItVec will be shorter than nbNodes
5925           }
5926         }
5927         newNodesItVec.push_back( nIt );
5928       }
5929       // make new elements
5930       if ( newNodesItVec.size() == nbNodes )
5931         sweepElement( elem, newNodesItVec, newElemsMap[elem], nbSteps, srcElems );
5932     }
5933   }
5934
5935   if ( theParams.ToMakeBoundary() ) {
5936     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], nbSteps, srcElems );
5937   }
5938   PGroupIDs newGroupIDs;
5939   if ( theParams.ToMakeGroups() )
5940     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
5941
5942   return newGroupIDs;
5943 }
5944
5945 //=======================================================================
5946 //function : ExtrusionAlongTrack
5947 //purpose  :
5948 //=======================================================================
5949 SMESH_MeshEditor::Extrusion_Error
5950 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet     theElements[2],
5951                                        SMESH_subMesh*       theTrack,
5952                                        const SMDS_MeshNode* theN1,
5953                                        const bool           theHasAngles,
5954                                        list<double>&        theAngles,
5955                                        const bool           theLinearVariation,
5956                                        const bool           theHasRefPoint,
5957                                        const gp_Pnt&        theRefPoint,
5958                                        const bool           theMakeGroups)
5959 {
5960   MESSAGE("ExtrusionAlongTrack");
5961   myLastCreatedElems.Clear();
5962   myLastCreatedNodes.Clear();
5963
5964   int aNbE;
5965   std::list<double> aPrms;
5966   TIDSortedElemSet::iterator itElem;
5967
5968   gp_XYZ aGC;
5969   TopoDS_Edge aTrackEdge;
5970   TopoDS_Vertex aV1, aV2;
5971
5972   SMDS_ElemIteratorPtr aItE;
5973   SMDS_NodeIteratorPtr aItN;
5974   SMDSAbs_ElementType aTypeE;
5975
5976   TNodeOfNodeListMap mapNewNodes;
5977
5978   // 1. Check data
5979   aNbE = theElements[0].size() + theElements[1].size();
5980   // nothing to do
5981   if ( !aNbE )
5982     return EXTR_NO_ELEMENTS;
5983
5984   // 1.1 Track Pattern
5985   ASSERT( theTrack );
5986
5987   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
5988
5989   aItE = pSubMeshDS->GetElements();
5990   while ( aItE->more() ) {
5991     const SMDS_MeshElement* pE = aItE->next();
5992     aTypeE = pE->GetType();
5993     // Pattern must contain links only
5994     if ( aTypeE != SMDSAbs_Edge )
5995       return EXTR_PATH_NOT_EDGE;
5996   }
5997
5998   list<SMESH_MeshEditor_PathPoint> fullList;
5999
6000   const TopoDS_Shape& aS = theTrack->GetSubShape();
6001   // Sub-shape for the Pattern must be an Edge or Wire
6002   if( aS.ShapeType() == TopAbs_EDGE ) {
6003     aTrackEdge = TopoDS::Edge( aS );
6004     // the Edge must not be degenerated
6005     if ( SMESH_Algo::isDegenerated( aTrackEdge ) )
6006       return EXTR_BAD_PATH_SHAPE;
6007     TopExp::Vertices( aTrackEdge, aV1, aV2 );
6008     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
6009     const SMDS_MeshNode* aN1 = aItN->next();
6010     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
6011     const SMDS_MeshNode* aN2 = aItN->next();
6012     // starting node must be aN1 or aN2
6013     if ( !( aN1 == theN1 || aN2 == theN1 ) )
6014       return EXTR_BAD_STARTING_NODE;
6015     aItN = pSubMeshDS->GetNodes();
6016     while ( aItN->more() ) {
6017       const SMDS_MeshNode* pNode = aItN->next();
6018       const SMDS_EdgePosition* pEPos =
6019         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
6020       double aT = pEPos->GetUParameter();
6021       aPrms.push_back( aT );
6022     }
6023     //Extrusion_Error err =
6024     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
6025   } else if( aS.ShapeType() == TopAbs_WIRE ) {
6026     list< SMESH_subMesh* > LSM;
6027     TopTools_SequenceOfShape Edges;
6028     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
6029     while(itSM->more()) {
6030       SMESH_subMesh* SM = itSM->next();
6031       LSM.push_back(SM);
6032       const TopoDS_Shape& aS = SM->GetSubShape();
6033       Edges.Append(aS);
6034     }
6035     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
6036     int startNid = theN1->GetID();
6037     TColStd_MapOfInteger UsedNums;
6038
6039     int NbEdges = Edges.Length();
6040     int i = 1;
6041     for(; i<=NbEdges; i++) {
6042       int k = 0;
6043       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
6044       for(; itLSM!=LSM.end(); itLSM++) {
6045         k++;
6046         if(UsedNums.Contains(k)) continue;
6047         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
6048         SMESH_subMesh* locTrack = *itLSM;
6049         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
6050         TopExp::Vertices( aTrackEdge, aV1, aV2 );
6051         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
6052         const SMDS_MeshNode* aN1 = aItN->next();
6053         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
6054         const SMDS_MeshNode* aN2 = aItN->next();
6055         // starting node must be aN1 or aN2
6056         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
6057         // 2. Collect parameters on the track edge
6058         aPrms.clear();
6059         aItN = locMeshDS->GetNodes();
6060         while ( aItN->more() ) {
6061           const SMDS_MeshNode* pNode = aItN->next();
6062           const SMDS_EdgePosition* pEPos =
6063             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
6064           double aT = pEPos->GetUParameter();
6065           aPrms.push_back( aT );
6066         }
6067         list<SMESH_MeshEditor_PathPoint> LPP;
6068         //Extrusion_Error err =
6069         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
6070         LLPPs.push_back(LPP);
6071         UsedNums.Add(k);
6072         // update startN for search following egde
6073         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
6074         else startNid = aN1->GetID();
6075         break;
6076       }
6077     }
6078     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
6079     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
6080     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
6081     for(; itPP!=firstList.end(); itPP++) {
6082       fullList.push_back( *itPP );
6083     }
6084     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
6085     fullList.pop_back();
6086     itLLPP++;
6087     for(; itLLPP!=LLPPs.end(); itLLPP++) {
6088       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
6089       itPP = currList.begin();
6090       SMESH_MeshEditor_PathPoint PP2 = currList.front();
6091       gp_Dir D1 = PP1.Tangent();
6092       gp_Dir D2 = PP2.Tangent();
6093       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
6094                            (D1.Z()+D2.Z())/2 ) );
6095       PP1.SetTangent(Dnew);
6096       fullList.push_back(PP1);
6097       itPP++;
6098       for(; itPP!=firstList.end(); itPP++) {
6099         fullList.push_back( *itPP );
6100       }
6101       PP1 = fullList.back();
6102       fullList.pop_back();
6103     }
6104     // if wire not closed
6105     fullList.push_back(PP1);
6106     // else ???
6107   }
6108   else {
6109     return EXTR_BAD_PATH_SHAPE;
6110   }
6111
6112   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
6113                           theHasRefPoint, theRefPoint, theMakeGroups);
6114 }
6115
6116
6117 //=======================================================================
6118 //function : ExtrusionAlongTrack
6119 //purpose  :
6120 //=======================================================================
6121 SMESH_MeshEditor::Extrusion_Error
6122 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet     theElements[2],
6123                                        SMESH_Mesh*          theTrack,
6124                                        const SMDS_MeshNode* theN1,
6125                                        const bool           theHasAngles,
6126                                        list<double>&        theAngles,
6127                                        const bool           theLinearVariation,
6128                                        const bool           theHasRefPoint,
6129                                        const gp_Pnt&        theRefPoint,
6130                                        const bool           theMakeGroups)
6131 {
6132   myLastCreatedElems.Clear();
6133   myLastCreatedNodes.Clear();
6134
6135   int aNbE;
6136   std::list<double> aPrms;
6137   TIDSortedElemSet::iterator itElem;
6138
6139   gp_XYZ aGC;
6140   TopoDS_Edge aTrackEdge;
6141   TopoDS_Vertex aV1, aV2;
6142
6143   SMDS_ElemIteratorPtr aItE;
6144   SMDS_NodeIteratorPtr aItN;
6145   SMDSAbs_ElementType aTypeE;
6146
6147   TNodeOfNodeListMap mapNewNodes;
6148
6149   // 1. Check data
6150   aNbE = theElements[0].size() + theElements[1].size();
6151   // nothing to do
6152   if ( !aNbE )
6153     return EXTR_NO_ELEMENTS;
6154
6155   // 1.1 Track Pattern
6156   ASSERT( theTrack );
6157
6158   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
6159
6160   aItE = pMeshDS->elementsIterator();
6161   while ( aItE->more() ) {
6162     const SMDS_MeshElement* pE = aItE->next();
6163     aTypeE = pE->GetType();
6164     // Pattern must contain links only
6165     if ( aTypeE != SMDSAbs_Edge )
6166       return EXTR_PATH_NOT_EDGE;
6167   }
6168
6169   list<SMESH_MeshEditor_PathPoint> fullList;
6170
6171   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
6172
6173   if ( !theTrack->HasShapeToMesh() ) {
6174     //Mesh without shape
6175     const SMDS_MeshNode* currentNode = NULL;
6176     const SMDS_MeshNode* prevNode = theN1;
6177     std::vector<const SMDS_MeshNode*> aNodesList;
6178     aNodesList.push_back(theN1);
6179     int nbEdges = 0, conn=0;
6180     const SMDS_MeshElement* prevElem = NULL;
6181     const SMDS_MeshElement* currentElem = NULL;
6182     int totalNbEdges = theTrack->NbEdges();
6183     SMDS_ElemIteratorPtr nIt;
6184
6185     //check start node
6186     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
6187       return EXTR_BAD_STARTING_NODE;
6188     }
6189
6190     conn = nbEdgeConnectivity(theN1);
6191     if( conn != 1 )
6192       return EXTR_PATH_NOT_EDGE;
6193
6194     aItE = theN1->GetInverseElementIterator();
6195     prevElem = aItE->next();
6196     currentElem = prevElem;
6197     //Get all nodes
6198     if(totalNbEdges == 1 ) {
6199       nIt = currentElem->nodesIterator();
6200       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
6201       if(currentNode == prevNode)
6202         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
6203       aNodesList.push_back(currentNode);
6204     } else {
6205       nIt = currentElem->nodesIterator();
6206       while( nIt->more() ) {
6207         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
6208         if(currentNode == prevNode)
6209           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
6210         aNodesList.push_back(currentNode);
6211
6212         //case of the closed mesh
6213         if(currentNode == theN1) {
6214           nbEdges++;
6215           break;
6216         }
6217
6218         conn = nbEdgeConnectivity(currentNode);
6219         if(conn > 2) {
6220           return EXTR_PATH_NOT_EDGE;
6221         }else if( conn == 1 && nbEdges > 0 ) {
6222           //End of the path
6223           nbEdges++;
6224           break;
6225         }else {
6226           prevNode = currentNode;
6227           aItE = currentNode->GetInverseElementIterator();
6228           currentElem = aItE->next();
6229           if( currentElem  == prevElem)
6230             currentElem = aItE->next();
6231           nIt = currentElem->nodesIterator();
6232           prevElem = currentElem;
6233           nbEdges++;
6234         }
6235       }
6236     }
6237
6238     if(nbEdges != totalNbEdges)
6239       return EXTR_PATH_NOT_EDGE;
6240
6241     TopTools_SequenceOfShape Edges;
6242     double x1,x2,y1,y2,z1,z2;
6243     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
6244     int startNid = theN1->GetID();
6245     for(int i = 1; i < aNodesList.size(); i++) {
6246       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
6247       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
6248       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
6249       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));
6250       list<SMESH_MeshEditor_PathPoint> LPP;
6251       aPrms.clear();
6252       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
6253       LLPPs.push_back(LPP);
6254       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
6255       else startNid = aNodesList[i-1]->GetID();
6256
6257     }
6258
6259     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
6260     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
6261     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
6262     for(; itPP!=firstList.end(); itPP++) {
6263       fullList.push_back( *itPP );
6264     }
6265
6266     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
6267     SMESH_MeshEditor_PathPoint PP2;
6268     fullList.pop_back();
6269     itLLPP++;
6270     for(; itLLPP!=LLPPs.end(); itLLPP++) {
6271       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
6272       itPP = currList.begin();
6273       PP2 = currList.front();
6274       gp_Dir D1 = PP1.Tangent();
6275       gp_Dir D2 = PP2.Tangent();
6276       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
6277                            (D1.Z()+D2.Z())/2 ) );
6278       PP1.SetTangent(Dnew);
6279       fullList.push_back(PP1);
6280       itPP++;
6281       for(; itPP!=currList.end(); itPP++) {
6282         fullList.push_back( *itPP );
6283       }
6284       PP1 = fullList.back();
6285       fullList.pop_back();
6286     }
6287     fullList.push_back(PP1);
6288
6289   } // Sub-shape for the Pattern must be an Edge or Wire
6290   else if( aS.ShapeType() == TopAbs_EDGE ) {
6291     aTrackEdge = TopoDS::Edge( aS );
6292     // the Edge must not be degenerated
6293     if ( SMESH_Algo::isDegenerated( aTrackEdge ) )
6294       return EXTR_BAD_PATH_SHAPE;
6295     TopExp::Vertices( aTrackEdge, aV1, aV2 );
6296     const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS );
6297     const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS );
6298     // starting node must be aN1 or aN2
6299     if ( !( aN1 == theN1 || aN2 == theN1 ) )
6300       return EXTR_BAD_STARTING_NODE;
6301     aItN = pMeshDS->nodesIterator();
6302     while ( aItN->more() ) {
6303       const SMDS_MeshNode* pNode = aItN->next();
6304       if( pNode==aN1 || pNode==aN2 ) continue;
6305       const SMDS_EdgePosition* pEPos =
6306         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
6307       double aT = pEPos->GetUParameter();
6308       aPrms.push_back( aT );
6309     }
6310     //Extrusion_Error err =
6311     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
6312   }
6313   else if( aS.ShapeType() == TopAbs_WIRE ) {
6314     list< SMESH_subMesh* > LSM;
6315     TopTools_SequenceOfShape Edges;
6316     TopExp_Explorer eExp(aS, TopAbs_EDGE);
6317     for(; eExp.More(); eExp.Next()) {
6318       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
6319       if( SMESH_Algo::isDegenerated(E) ) continue;
6320       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
6321       if(SM) {
6322         LSM.push_back(SM);
6323         Edges.Append(E);
6324       }
6325     }
6326     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
6327     TopoDS_Vertex aVprev;
6328     TColStd_MapOfInteger UsedNums;
6329     int NbEdges = Edges.Length();
6330     int i = 1;
6331     for(; i<=NbEdges; i++) {
6332       int k = 0;
6333       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
6334       for(; itLSM!=LSM.end(); itLSM++) {
6335         k++;
6336         if(UsedNums.Contains(k)) continue;
6337         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
6338         SMESH_subMesh* locTrack = *itLSM;
6339         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
6340         TopExp::Vertices( aTrackEdge, aV1, aV2 );
6341         bool aN1isOK = false, aN2isOK = false;
6342         if ( aVprev.IsNull() ) {
6343           // if previous vertex is not yet defined, it means that we in the beginning of wire
6344           // and we have to find initial vertex corresponding to starting node theN1
6345           const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS );
6346           const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS );
6347           // starting node must be aN1 or aN2
6348           aN1isOK = ( aN1 && aN1 == theN1 );
6349           aN2isOK = ( aN2 && aN2 == theN1 );
6350         }
6351         else {
6352           // we have specified ending vertex of the previous edge on the previous iteration
6353           // and we have just to check that it corresponds to any vertex in current segment
6354           aN1isOK = aVprev.IsSame( aV1 );
6355           aN2isOK = aVprev.IsSame( aV2 );
6356         }
6357         if ( !aN1isOK && !aN2isOK ) continue;
6358         // 2. Collect parameters on the track edge
6359         aPrms.clear();
6360         aItN = locMeshDS->GetNodes();
6361         while ( aItN->more() ) {
6362           const SMDS_MeshNode*     pNode = aItN->next();
6363           const SMDS_EdgePosition* pEPos =
6364             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
6365           double aT = pEPos->GetUParameter();
6366           aPrms.push_back( aT );
6367         }
6368         list<SMESH_MeshEditor_PathPoint> LPP;
6369         //Extrusion_Error err =
6370         MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
6371         LLPPs.push_back(LPP);
6372         UsedNums.Add(k);
6373         // update startN for search following egde
6374         if ( aN1isOK ) aVprev = aV2;
6375         else           aVprev = aV1;
6376         break;
6377       }
6378     }
6379     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
6380     list<SMESH_MeshEditor_PathPoint>& firstList = *itLLPP;
6381     fullList.splice( fullList.end(), firstList );
6382
6383     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
6384     fullList.pop_back();
6385     itLLPP++;
6386     for(; itLLPP!=LLPPs.end(); itLLPP++) {
6387       list<SMESH_MeshEditor_PathPoint>& currList = *itLLPP;
6388       SMESH_MeshEditor_PathPoint PP2 = currList.front();
6389       gp_Dir D1 = PP1.Tangent();
6390       gp_Dir D2 = PP2.Tangent();
6391       gp_Dir Dnew( ( D1.XYZ() + D2.XYZ() ) / 2 );
6392       PP1.SetTangent(Dnew);
6393       fullList.push_back(PP1);
6394       fullList.splice( fullList.end(), currList, ++currList.begin(), currList.end() );
6395       PP1 = fullList.back();
6396       fullList.pop_back();
6397     }
6398     // if wire not closed
6399     fullList.push_back(PP1);
6400     // else ???
6401   }
6402   else {
6403     return EXTR_BAD_PATH_SHAPE;
6404   }
6405
6406   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
6407                           theHasRefPoint, theRefPoint, theMakeGroups);
6408 }
6409
6410
6411 //=======================================================================
6412 //function : MakeEdgePathPoints
6413 //purpose  : auxilary for ExtrusionAlongTrack
6414 //=======================================================================
6415 SMESH_MeshEditor::Extrusion_Error
6416 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>&                aPrms,
6417                                      const TopoDS_Edge&                aTrackEdge,
6418                                      bool                              FirstIsStart,
6419                                      list<SMESH_MeshEditor_PathPoint>& LPP)
6420 {
6421   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
6422   aTolVec=1.e-7;
6423   aTolVec2=aTolVec*aTolVec;
6424   double aT1, aT2;
6425   TopoDS_Vertex aV1, aV2;
6426   TopExp::Vertices( aTrackEdge, aV1, aV2 );
6427   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
6428   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
6429   // 2. Collect parameters on the track edge
6430   aPrms.push_front( aT1 );
6431   aPrms.push_back( aT2 );
6432   // sort parameters
6433   aPrms.sort();
6434   if( FirstIsStart ) {
6435     if ( aT1 > aT2 ) {
6436       aPrms.reverse();
6437     }
6438   }
6439   else {
6440     if ( aT2 > aT1 ) {
6441       aPrms.reverse();
6442     }
6443   }
6444   // 3. Path Points
6445   SMESH_MeshEditor_PathPoint aPP;
6446   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
6447   std::list<double>::iterator aItD = aPrms.begin();
6448   for(; aItD != aPrms.end(); ++aItD) {
6449     double aT = *aItD;
6450     gp_Pnt aP3D;
6451     gp_Vec aVec;
6452     aC3D->D1( aT, aP3D, aVec );
6453     aL2 = aVec.SquareMagnitude();
6454     if ( aL2 < aTolVec2 )
6455       return EXTR_CANT_GET_TANGENT;
6456     gp_Dir aTgt( aVec );
6457     aPP.SetPnt( aP3D );
6458     aPP.SetTangent( aTgt );
6459     aPP.SetParameter( aT );
6460     LPP.push_back(aPP);
6461   }
6462   return EXTR_OK;
6463 }
6464
6465
6466 //=======================================================================
6467 //function : MakeExtrElements
6468 //purpose  : auxilary for ExtrusionAlongTrack
6469 //=======================================================================
6470 SMESH_MeshEditor::Extrusion_Error
6471 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet                  theElemSets[2],
6472                                    list<SMESH_MeshEditor_PathPoint>& fullList,
6473                                    const bool                        theHasAngles,
6474                                    list<double>&                     theAngles,
6475                                    const bool                        theLinearVariation,
6476                                    const bool                        theHasRefPoint,
6477                                    const gp_Pnt&                     theRefPoint,
6478                                    const bool                        theMakeGroups)
6479 {
6480   const int aNbTP = fullList.size();
6481   // Angles
6482   if( theHasAngles && !theAngles.empty() && theLinearVariation )
6483     LinearAngleVariation(aNbTP-1, theAngles);
6484   // fill vector of path points with angles
6485   vector<SMESH_MeshEditor_PathPoint> aPPs;
6486   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
6487   list<double>::iterator                 itAngles = theAngles.begin();
6488   aPPs.push_back( *itPP++ );
6489   for( ; itPP != fullList.end(); itPP++) {
6490     aPPs.push_back( *itPP );
6491     if ( theHasAngles && itAngles != theAngles.end() )
6492       aPPs.back().SetAngle( *itAngles++ );
6493   }
6494
6495   TNodeOfNodeListMap   mapNewNodes;
6496   TElemOfVecOfNnlmiMap mapElemNewNodes;
6497   TTElemOfElemListMap  newElemsMap;
6498   TIDSortedElemSet::iterator itElem;
6499   // source elements for each generated one
6500   SMESH_SequenceOfElemPtr srcElems, srcNodes;
6501
6502   // 3. Center of rotation aV0
6503   gp_Pnt aV0 = theRefPoint;
6504   if ( !theHasRefPoint )
6505   {
6506     gp_XYZ aGC( 0.,0.,0. );
6507     TIDSortedElemSet newNodes;
6508
6509     for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
6510     {
6511       TIDSortedElemSet& theElements = theElemSets[ is2ndSet ];
6512       itElem = theElements.begin();
6513       for ( ; itElem != theElements.end(); itElem++ ) {
6514         const SMDS_MeshElement* elem = *itElem;
6515
6516         SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6517         while ( itN->more() ) {
6518           const SMDS_MeshElement* node = itN->next();
6519           if ( newNodes.insert( node ).second )
6520             aGC += SMESH_TNodeXYZ( node );
6521         }
6522       }
6523     }
6524     aGC /= newNodes.size();
6525     aV0.SetXYZ( aGC );
6526   } // if (!theHasRefPoint) {
6527
6528   // 4. Processing the elements
6529   SMESHDS_Mesh* aMesh = GetMeshDS();
6530
6531   setElemsFirst( theElemSets );
6532   for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
6533   {
6534     TIDSortedElemSet& theElements = theElemSets[ is2ndSet ];
6535     for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
6536       // check element type
6537       const SMDS_MeshElement* elem = *itElem;
6538       if ( !elem )
6539         continue;
6540       // SMDSAbs_ElementType aTypeE = elem->GetType();
6541       // if ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge )
6542       //   continue;
6543
6544       vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
6545       newNodesItVec.reserve( elem->NbNodes() );
6546
6547       // loop on elem nodes
6548       int nodeIndex = -1;
6549       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6550       while ( itN->more() )
6551       {
6552         ++nodeIndex;
6553         // check if a node has been already processed
6554         const SMDS_MeshNode* node =
6555           static_cast<const SMDS_MeshNode*>( itN->next() );
6556         TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
6557         if ( nIt == mapNewNodes.end() ) {
6558           nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
6559           list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
6560
6561           // make new nodes
6562           Standard_Real aAngle1x, aAngleT1T0, aTolAng;
6563           gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
6564           gp_Ax1 anAx1, anAxT1T0;
6565           gp_Dir aDT1x, aDT0x, aDT1T0;
6566
6567           aTolAng=1.e-4;
6568
6569           aV0x = aV0;
6570           aPN0 = SMESH_TNodeXYZ( node );
6571
6572           const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
6573           aP0x = aPP0.Pnt();
6574           aDT0x= aPP0.Tangent();
6575           //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
6576
6577           for ( int j = 1; j < aNbTP; ++j ) {
6578             const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
6579             aP1x     = aPP1.Pnt();
6580             aDT1x    = aPP1.Tangent();
6581             aAngle1x = aPP1.Angle();
6582
6583             gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
6584             // Translation
6585             gp_Vec aV01x( aP0x, aP1x );
6586             aTrsf.SetTranslation( aV01x );
6587
6588             // traslated point
6589             aV1x = aV0x.Transformed( aTrsf );
6590             aPN1 = aPN0.Transformed( aTrsf );
6591
6592             // rotation 1 [ T1,T0 ]
6593             aAngleT1T0=-aDT1x.Angle( aDT0x );
6594             if (fabs(aAngleT1T0) > aTolAng) {
6595               aDT1T0=aDT1x^aDT0x;
6596               anAxT1T0.SetLocation( aV1x );
6597               anAxT1T0.SetDirection( aDT1T0 );
6598               aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
6599
6600               aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
6601             }
6602
6603             // rotation 2
6604             if ( theHasAngles ) {
6605               anAx1.SetLocation( aV1x );
6606               anAx1.SetDirection( aDT1x );
6607               aTrsfRot.SetRotation( anAx1, aAngle1x );
6608
6609               aPN1 = aPN1.Transformed( aTrsfRot );
6610             }
6611
6612             // make new node
6613             //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
6614             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
6615               // create additional node
6616               double x = ( aPN1.X() + aPN0.X() )/2.;
6617               double y = ( aPN1.Y() + aPN0.Y() )/2.;
6618               double z = ( aPN1.Z() + aPN0.Z() )/2.;
6619               const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
6620               myLastCreatedNodes.Append(newNode);
6621               srcNodes.Append( node );
6622               listNewNodes.push_back( newNode );
6623             }
6624             const SMDS_MeshNode* newNode = aMesh->AddNode( aPN1.X(), aPN1.Y(), aPN1.Z() );
6625             myLastCreatedNodes.Append(newNode);
6626             srcNodes.Append( node );
6627             listNewNodes.push_back( newNode );
6628
6629             aPN0 = aPN1;
6630             aP0x = aP1x;
6631             aV0x = aV1x;
6632             aDT0x = aDT1x;
6633           }
6634         }
6635
6636         else {
6637           // if current elem is quadratic and current node is not medium
6638           // we have to check - may be it is needed to insert additional nodes
6639           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
6640             list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
6641             if(listNewNodes.size()==aNbTP-1) {
6642               vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
6643               gp_XYZ P(node->X(), node->Y(), node->Z());
6644               list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
6645               int i;
6646               for(i=0; i<aNbTP-1; i++) {
6647                 const SMDS_MeshNode* N = *it;
6648                 double x = ( N->X() + P.X() )/2.;
6649                 double y = ( N->Y() + P.Y() )/2.;
6650                 double z = ( N->Z() + P.Z() )/2.;
6651                 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
6652                 srcNodes.Append( node );
6653                 myLastCreatedNodes.Append(newN);
6654                 aNodes[2*i] = newN;
6655                 aNodes[2*i+1] = N;
6656                 P = gp_XYZ(N->X(),N->Y(),N->Z());
6657               }
6658               listNewNodes.clear();
6659               for(i=0; i<2*(aNbTP-1); i++) {
6660                 listNewNodes.push_back(aNodes[i]);
6661               }
6662             }
6663           }
6664         }
6665
6666         newNodesItVec.push_back( nIt );
6667       }
6668       // make new elements
6669       //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
6670       //              newNodesItVec[0]->second.size(), myLastCreatedElems );
6671       sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
6672     }
6673   }
6674
6675   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], aNbTP-1, srcElems );
6676
6677   if ( theMakeGroups )
6678     generateGroups( srcNodes, srcElems, "extruded");
6679
6680   return EXTR_OK;
6681 }
6682
6683
6684 //=======================================================================
6685 //function : LinearAngleVariation
6686 //purpose  : auxilary for ExtrusionAlongTrack
6687 //=======================================================================
6688 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
6689                                             list<double>& Angles)
6690 {
6691   int nbAngles = Angles.size();
6692   if( nbSteps > nbAngles ) {
6693     vector<double> theAngles(nbAngles);
6694     list<double>::iterator it = Angles.begin();
6695     int i = -1;
6696     for(; it!=Angles.end(); it++) {
6697       i++;
6698       theAngles[i] = (*it);
6699     }
6700     list<double> res;
6701     double rAn2St = double( nbAngles ) / double( nbSteps );
6702     double angPrev = 0, angle;
6703     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
6704       double angCur = rAn2St * ( iSt+1 );
6705       double angCurFloor  = floor( angCur );
6706       double angPrevFloor = floor( angPrev );
6707       if ( angPrevFloor == angCurFloor )
6708         angle = rAn2St * theAngles[ int( angCurFloor ) ];
6709       else {
6710         int iP = int( angPrevFloor );
6711         double angPrevCeil = ceil(angPrev);
6712         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
6713
6714         int iC = int( angCurFloor );
6715         if ( iC < nbAngles )
6716           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
6717
6718         iP = int( angPrevCeil );
6719         while ( iC-- > iP )
6720           angle += theAngles[ iC ];
6721       }
6722       res.push_back(angle);
6723       angPrev = angCur;
6724     }
6725     Angles.clear();
6726     it = res.begin();
6727     for(; it!=res.end(); it++)
6728       Angles.push_back( *it );
6729   }
6730 }
6731
6732
6733 //================================================================================
6734 /*!
6735  * \brief Move or copy theElements applying theTrsf to their nodes
6736  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
6737  *  \param theTrsf - transformation to apply
6738  *  \param theCopy - if true, create translated copies of theElems
6739  *  \param theMakeGroups - if true and theCopy, create translated groups
6740  *  \param theTargetMesh - mesh to copy translated elements into
6741  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
6742  */
6743 //================================================================================
6744
6745 SMESH_MeshEditor::PGroupIDs
6746 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
6747                              const gp_Trsf&     theTrsf,
6748                              const bool         theCopy,
6749                              const bool         theMakeGroups,
6750                              SMESH_Mesh*        theTargetMesh)
6751 {
6752   myLastCreatedElems.Clear();
6753   myLastCreatedNodes.Clear();
6754
6755   bool needReverse = false;
6756   string groupPostfix;
6757   switch ( theTrsf.Form() ) {
6758   case gp_PntMirror:
6759     MESSAGE("gp_PntMirror");
6760     needReverse = true;
6761     groupPostfix = "mirrored";
6762     break;
6763   case gp_Ax1Mirror:
6764     MESSAGE("gp_Ax1Mirror");
6765     groupPostfix = "mirrored";
6766     break;
6767   case gp_Ax2Mirror:
6768     MESSAGE("gp_Ax2Mirror");
6769     needReverse = true;
6770     groupPostfix = "mirrored";
6771     break;
6772   case gp_Rotation:
6773     MESSAGE("gp_Rotation");
6774     groupPostfix = "rotated";
6775     break;
6776   case gp_Translation:
6777     MESSAGE("gp_Translation");
6778     groupPostfix = "translated";
6779     break;
6780   case gp_Scale:
6781     MESSAGE("gp_Scale");
6782     groupPostfix = "scaled";
6783     break;
6784   case gp_CompoundTrsf: // different scale by axis
6785     MESSAGE("gp_CompoundTrsf");
6786     groupPostfix = "scaled";
6787     break;
6788   default:
6789     MESSAGE("default");
6790     needReverse = false;
6791     groupPostfix = "transformed";
6792   }
6793
6794   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
6795   SMESHDS_Mesh* aMesh    = GetMeshDS();
6796
6797   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
6798   SMESH_MeshEditor* editor = theTargetMesh ? & targetMeshEditor : theCopy ? this : 0;
6799   SMESH_MeshEditor::ElemFeatures elemType;
6800
6801   // map old node to new one
6802   TNodeNodeMap nodeMap;
6803
6804   // elements sharing moved nodes; those of them which have all
6805   // nodes mirrored but are not in theElems are to be reversed
6806   TIDSortedElemSet inverseElemSet;
6807
6808   // source elements for each generated one
6809   SMESH_SequenceOfElemPtr srcElems, srcNodes;
6810
6811   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
6812   TIDSortedElemSet orphanNode;
6813
6814   if ( theElems.empty() ) // transform the whole mesh
6815   {
6816     // add all elements
6817     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
6818     while ( eIt->more() ) theElems.insert( eIt->next() );
6819     // add orphan nodes
6820     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
6821     while ( nIt->more() )
6822     {
6823       const SMDS_MeshNode* node = nIt->next();
6824       if ( node->NbInverseElements() == 0)
6825         orphanNode.insert( node );
6826     }
6827   }
6828
6829   // loop on elements to transform nodes : first orphan nodes then elems
6830   TIDSortedElemSet::iterator itElem;
6831   TIDSortedElemSet *elements[] = { &orphanNode, &theElems };
6832   for (int i=0; i<2; i++)
6833     for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ )
6834     {
6835       const SMDS_MeshElement* elem = *itElem;
6836       if ( !elem )
6837         continue;
6838
6839       // loop on elem nodes
6840       double coord[3];
6841       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6842       while ( itN->more() )
6843       {
6844         const SMDS_MeshNode* node = cast2Node( itN->next() );
6845         // check if a node has been already transformed
6846         pair<TNodeNodeMap::iterator,bool> n2n_isnew =
6847           nodeMap.insert( make_pair ( node, node ));
6848         if ( !n2n_isnew.second )
6849           continue;
6850
6851         node->GetXYZ( coord );
6852         theTrsf.Transforms( coord[0], coord[1], coord[2] );
6853         if ( theTargetMesh ) {
6854           const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
6855           n2n_isnew.first->second = newNode;
6856           myLastCreatedNodes.Append(newNode);
6857           srcNodes.Append( node );
6858         }
6859         else if ( theCopy ) {
6860           const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
6861           n2n_isnew.first->second = newNode;
6862           myLastCreatedNodes.Append(newNode);
6863           srcNodes.Append( node );
6864         }
6865         else {
6866           aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
6867           // node position on shape becomes invalid
6868           const_cast< SMDS_MeshNode* > ( node )->SetPosition
6869             ( SMDS_SpacePosition::originSpacePosition() );
6870         }
6871
6872         // keep inverse elements
6873         if ( !theCopy && !theTargetMesh && needReverse ) {
6874           SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
6875           while ( invElemIt->more() ) {
6876             const SMDS_MeshElement* iel = invElemIt->next();
6877             inverseElemSet.insert( iel );
6878           }
6879         }
6880       }
6881     } // loop on elems in { &orphanNode, &theElems };
6882
6883   // either create new elements or reverse mirrored ones
6884   if ( !theCopy && !needReverse && !theTargetMesh )
6885     return PGroupIDs();
6886
6887   theElems.insert( inverseElemSet.begin(),inverseElemSet.end() );
6888
6889   // Replicate or reverse elements
6890
6891   std::vector<int> iForw;
6892   vector<const SMDS_MeshNode*> nodes;
6893   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
6894   {
6895     const SMDS_MeshElement* elem = *itElem;
6896     if ( !elem ) continue;
6897
6898     SMDSAbs_GeometryType geomType = elem->GetGeomType();
6899     int                  nbNodes  = elem->NbNodes();
6900     if ( geomType == SMDSGeom_NONE ) continue; // node
6901
6902     nodes.resize( nbNodes );
6903
6904     if ( geomType == SMDSGeom_POLYHEDRA )  // ------------------ polyhedral volume
6905     {
6906       const SMDS_VtkVolume* aPolyedre = dynamic_cast<const SMDS_VtkVolume*>( elem );
6907       if (!aPolyedre)
6908         continue;
6909       nodes.clear();
6910       bool allTransformed = true;
6911       int nbFaces = aPolyedre->NbFaces();
6912       for (int iface = 1; iface <= nbFaces && allTransformed; iface++)
6913       {
6914         int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6915         for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++)
6916         {
6917           const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
6918           TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
6919           if ( nodeMapIt == nodeMap.end() )
6920             allTransformed = false; // not all nodes transformed
6921           else
6922             nodes.push_back((*nodeMapIt).second);
6923         }
6924         if ( needReverse && allTransformed )
6925           std::reverse( nodes.end() - nbFaceNodes, nodes.end() );
6926       }
6927       if ( !allTransformed )
6928         continue; // not all nodes transformed
6929     }
6930     else // ----------------------- the rest element types
6931     {
6932       while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
6933       const vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType(), nbNodes );
6934       const vector<int>&    i = needReverse ? iRev : iForw;
6935
6936       // find transformed nodes
6937       int iNode = 0;
6938       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6939       while ( itN->more() ) {
6940         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
6941         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
6942         if ( nodeMapIt == nodeMap.end() )
6943           break; // not all nodes transformed
6944         nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
6945       }
6946       if ( iNode != nbNodes )
6947         continue; // not all nodes transformed
6948     }
6949
6950     if ( editor ) {
6951       // copy in this or a new mesh
6952       if ( editor->AddElement( nodes, elemType.Init( elem, /*basicOnly=*/false )))
6953         srcElems.Append( elem );
6954     }
6955     else {
6956       // reverse element as it was reversed by transformation
6957       if ( nbNodes > 2 )
6958         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
6959     }
6960
6961   } // loop on elements
6962
6963   if ( editor && editor != this )
6964     myLastCreatedElems = editor->myLastCreatedElems;
6965
6966   PGroupIDs newGroupIDs;
6967
6968   if ( ( theMakeGroups && theCopy ) ||
6969        ( theMakeGroups && theTargetMesh ) )
6970     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh, false );
6971
6972   return newGroupIDs;
6973 }
6974
6975 //=======================================================================
6976 /*!
6977  * \brief Create groups of elements made during transformation
6978  *  \param nodeGens - nodes making corresponding myLastCreatedNodes
6979  *  \param elemGens - elements making corresponding myLastCreatedElems
6980  *  \param postfix - to append to names of new groups
6981  *  \param targetMesh - mesh to create groups in
6982  *  \param topPresent - is there "top" elements that are created by sweeping
6983  */
6984 //=======================================================================
6985
6986 SMESH_MeshEditor::PGroupIDs
6987 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
6988                                  const SMESH_SequenceOfElemPtr& elemGens,
6989                                  const std::string&             postfix,
6990                                  SMESH_Mesh*                    targetMesh,
6991                                  const bool                     topPresent)
6992 {
6993   PGroupIDs newGroupIDs( new list<int> );
6994   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6995
6996   // Sort existing groups by types and collect their names
6997
6998   // containers to store an old group and generated new ones;
6999   // 1st new group is for result elems of different type than a source one;
7000   // 2nd new group is for same type result elems ("top" group at extrusion)
7001   using boost::tuple;
7002   using boost::make_tuple;
7003   typedef tuple< SMESHDS_GroupBase*, SMESHDS_Group*, SMESHDS_Group* > TOldNewGroup;
7004   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
7005   vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups
7006   // group names
7007   set< string > groupNames;
7008
7009   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
7010   if ( !groupIt->more() ) return newGroupIDs;
7011
7012   int newGroupID = mesh->GetGroupIds().back()+1;
7013   while ( groupIt->more() )
7014   {
7015     SMESH_Group * group = groupIt->next();
7016     if ( !group ) continue;
7017     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
7018     if ( !groupDS || groupDS->IsEmpty() ) continue;
7019     groupNames.insert    ( group->GetName() );
7020     groupDS->SetStoreName( group->GetName() );
7021     const SMDSAbs_ElementType type = groupDS->GetType();
7022     SMESHDS_Group* newGroup    = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
7023     SMESHDS_Group* newTopGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
7024     groupsByType[ type ].push_back( make_tuple( groupDS, newGroup, newTopGroup ));
7025     orderedOldNewGroups.push_back( & groupsByType[ type ].back() );
7026   }
7027
7028   // Loop on nodes and elements to add them in new groups
7029
7030   vector< const SMDS_MeshElement* > resultElems;
7031   for ( int isNodes = 0; isNodes < 2; ++isNodes )
7032   {
7033     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
7034     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
7035     if ( gens.Length() != elems.Length() )
7036       throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args");
7037
7038     // loop on created elements
7039     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
7040     {
7041       const SMDS_MeshElement* sourceElem = gens( iElem );
7042       if ( !sourceElem ) {
7043         MESSAGE("generateGroups(): NULL source element");
7044         continue;
7045       }
7046       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
7047       if ( groupsOldNew.empty() ) { // no groups of this type at all
7048         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
7049           ++iElem; // skip all elements made by sourceElem
7050         continue;
7051       }
7052       // collect all elements made by the iElem-th sourceElem
7053       resultElems.clear();
7054       if ( const SMDS_MeshElement* resElem = elems( iElem ))
7055         if ( resElem != sourceElem )
7056           resultElems.push_back( resElem );
7057       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
7058         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
7059           if ( resElem != sourceElem )
7060             resultElems.push_back( resElem );
7061
7062       const SMDS_MeshElement* topElem = 0;
7063       if ( isNodes ) // there must be a top element
7064       {
7065         topElem = resultElems.back();
7066         resultElems.pop_back();
7067       }
7068       else
7069       {
7070         vector< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin();
7071         for ( ; resElemIt != resultElems.rend() ; ++resElemIt )
7072           if ( (*resElemIt)->GetType() == sourceElem->GetType() )
7073           {
7074             topElem = *resElemIt;
7075             *resElemIt = 0; // erase *resElemIt
7076             break;
7077           }
7078       }
7079       // add resultElems to groups originted from ones the sourceElem belongs to
7080       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
7081       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
7082       {
7083         SMESHDS_GroupBase* oldGroup = gOldNew->get<0>();
7084         if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup
7085         {
7086           // fill in a new group
7087           SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup();
7088           vector< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
7089           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
7090             if ( *resElemIt )
7091               newGroup.Add( *resElemIt );
7092
7093           // fill a "top" group
7094           if ( topElem )
7095           {
7096             SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup();
7097             newTopGroup.Add( topElem );
7098          }
7099         }
7100       }
7101     } // loop on created elements
7102   }// loop on nodes and elements
7103
7104   // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups
7105
7106   list<int> topGrouIds;
7107   for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i )
7108   {
7109     SMESHDS_GroupBase* oldGroupDS =   orderedOldNewGroups[i]->get<0>();
7110     SMESHDS_Group*   newGroups[2] = { orderedOldNewGroups[i]->get<1>(),
7111                                       orderedOldNewGroups[i]->get<2>() };
7112     for ( int is2nd = 0; is2nd < 2; ++is2nd )
7113     {
7114       SMESHDS_Group* newGroupDS = newGroups[ is2nd ];
7115       if ( newGroupDS->IsEmpty() )
7116       {
7117         mesh->GetMeshDS()->RemoveGroup( newGroupDS );
7118       }
7119       else
7120       {
7121         // set group type
7122         newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
7123
7124         // make a name
7125         const bool isTop = ( topPresent &&
7126                              newGroupDS->GetType() == oldGroupDS->GetType() &&
7127                              is2nd );
7128
7129         string name = oldGroupDS->GetStoreName();
7130         { // remove trailing whitespaces (issue 22599)
7131           size_t size = name.size();
7132           while ( size > 1 && isspace( name[ size-1 ]))
7133             --size;
7134           if ( size != name.size() )
7135           {
7136             name.resize( size );
7137             oldGroupDS->SetStoreName( name.c_str() );
7138           }
7139         }
7140         if ( !targetMesh ) {
7141           string suffix = ( isTop ? "top": postfix.c_str() );
7142           name += "_";
7143           name += suffix;
7144           int nb = 1;
7145           while ( !groupNames.insert( name ).second ) // name exists
7146             name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << suffix << "_" << nb++;
7147         }
7148         else if ( isTop ) {
7149           name += "_top";
7150         }
7151         newGroupDS->SetStoreName( name.c_str() );
7152
7153         // make a SMESH_Groups
7154         mesh->AddGroup( newGroupDS );
7155         if ( isTop )
7156           topGrouIds.push_back( newGroupDS->GetID() );
7157         else
7158           newGroupIDs->push_back( newGroupDS->GetID() );
7159       }
7160     }
7161   }
7162   newGroupIDs->splice( newGroupIDs->end(), topGrouIds );
7163
7164   return newGroupIDs;
7165 }
7166
7167 //================================================================================
7168 /*!
7169  *  * \brief Return list of group of nodes close to each other within theTolerance
7170  *  *        Search among theNodes or in the whole mesh if theNodes is empty using
7171  *  *        an Octree algorithm
7172  *  \param [in,out] theNodes - the nodes to treat
7173  *  \param [in]     theTolerance - the tolerance
7174  *  \param [out]    theGroupsOfNodes - the result groups of coincident nodes
7175  *  \param [in]     theSeparateCornersAndMedium - if \c true, in quadratic mesh puts 
7176  *         corner and medium nodes in separate groups
7177  */
7178 //================================================================================
7179
7180 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
7181                                             const double         theTolerance,
7182                                             TListOfListOfNodes & theGroupsOfNodes,
7183                                             bool                 theSeparateCornersAndMedium)
7184 {
7185   myLastCreatedElems.Clear();
7186   myLastCreatedNodes.Clear();
7187
7188   if ( myMesh->NbEdges  ( ORDER_QUADRATIC ) +
7189        myMesh->NbFaces  ( ORDER_QUADRATIC ) +
7190        myMesh->NbVolumes( ORDER_QUADRATIC ) == 0 )
7191     theSeparateCornersAndMedium = false;
7192
7193   TIDSortedNodeSet& corners = theNodes;
7194   TIDSortedNodeSet  medium;
7195
7196   if ( theNodes.empty() ) // get all nodes in the mesh
7197   {
7198     TIDSortedNodeSet* nodes[2] = { &corners, &medium };
7199     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
7200     if ( theSeparateCornersAndMedium )
7201       while ( nIt->more() )
7202       {
7203         const SMDS_MeshNode* n = nIt->next();
7204         TIDSortedNodeSet* & nodeSet = nodes[ SMESH_MesherHelper::IsMedium( n )];
7205         nodeSet->insert( nodeSet->end(), n );
7206       }
7207     else
7208       while ( nIt->more() )
7209         theNodes.insert( theNodes.end(),nIt->next() );
7210   }
7211   else if ( theSeparateCornersAndMedium ) // separate corners from medium nodes
7212   {
7213     TIDSortedNodeSet::iterator nIt = corners.begin();
7214     while ( nIt != corners.end() )
7215       if ( SMESH_MesherHelper::IsMedium( *nIt ))
7216       {
7217         medium.insert( medium.end(), *nIt );
7218         corners.erase( nIt++ );
7219       }
7220       else
7221       {
7222         ++nIt;
7223       }
7224   }
7225
7226   if ( !corners.empty() )
7227     SMESH_OctreeNode::FindCoincidentNodes ( corners, &theGroupsOfNodes, theTolerance );
7228   if ( !medium.empty() )
7229     SMESH_OctreeNode::FindCoincidentNodes ( medium, &theGroupsOfNodes, theTolerance );
7230 }
7231
7232 //=======================================================================
7233 //function : SimplifyFace
7234 //purpose  : split a chain of nodes into several closed chains
7235 //=======================================================================
7236
7237 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *>& faceNodes,
7238                                     vector<const SMDS_MeshNode *>&       poly_nodes,
7239                                     vector<int>&                         quantities) const
7240 {
7241   int nbNodes = faceNodes.size();
7242
7243   if (nbNodes < 3)
7244     return 0;
7245
7246   set<const SMDS_MeshNode*> nodeSet;
7247
7248   // get simple seq of nodes
7249   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7250   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7251   int iSimple = 0, nbUnique = 0;
7252
7253   simpleNodes[iSimple++] = faceNodes[0];
7254   nbUnique++;
7255   for (int iCur = 1; iCur < nbNodes; iCur++) {
7256     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7257       simpleNodes[iSimple++] = faceNodes[iCur];
7258       if (nodeSet.insert( faceNodes[iCur] ).second)
7259         nbUnique++;
7260     }
7261   }
7262   int nbSimple = iSimple;
7263   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7264     nbSimple--;
7265     iSimple--;
7266   }
7267
7268   if (nbUnique < 3)
7269     return 0;
7270
7271   // separate loops
7272   int nbNew = 0;
7273   bool foundLoop = (nbSimple > nbUnique);
7274   while (foundLoop) {
7275     foundLoop = false;
7276     set<const SMDS_MeshNode*> loopSet;
7277     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7278       const SMDS_MeshNode* n = simpleNodes[iSimple];
7279       if (!loopSet.insert( n ).second) {
7280         foundLoop = true;
7281
7282         // separate loop
7283         int iC = 0, curLast = iSimple;
7284         for (; iC < curLast; iC++) {
7285           if (simpleNodes[iC] == n) break;
7286         }
7287         int loopLen = curLast - iC;
7288         if (loopLen > 2) {
7289           // create sub-element
7290           nbNew++;
7291           quantities.push_back(loopLen);
7292           for (; iC < curLast; iC++) {
7293             poly_nodes.push_back(simpleNodes[iC]);
7294           }
7295         }
7296         // shift the rest nodes (place from the first loop position)
7297         for (iC = curLast + 1; iC < nbSimple; iC++) {
7298           simpleNodes[iC - loopLen] = simpleNodes[iC];
7299         }
7300         nbSimple -= loopLen;
7301         iSimple -= loopLen;
7302       }
7303     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7304   } // while (foundLoop)
7305
7306   if (iSimple > 2) {
7307     nbNew++;
7308     quantities.push_back(iSimple);
7309     for (int i = 0; i < iSimple; i++)
7310       poly_nodes.push_back(simpleNodes[i]);
7311   }
7312
7313   return nbNew;
7314 }
7315
7316 //=======================================================================
7317 //function : MergeNodes
7318 //purpose  : In each group, the cdr of nodes are substituted by the first one
7319 //           in all elements.
7320 //=======================================================================
7321
7322 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7323 {
7324   MESSAGE("MergeNodes");
7325   myLastCreatedElems.Clear();
7326   myLastCreatedNodes.Clear();
7327
7328   SMESHDS_Mesh* aMesh = GetMeshDS();
7329
7330   TNodeNodeMap nodeNodeMap; // node to replace - new node
7331   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7332   list< int > rmElemIds, rmNodeIds;
7333
7334   // Fill nodeNodeMap and elems
7335
7336   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7337   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7338     list<const SMDS_MeshNode*>& nodes = *grIt;
7339     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7340     const SMDS_MeshNode* nToKeep = *nIt;
7341     //MESSAGE("node to keep " << nToKeep->GetID());
7342     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7343       const SMDS_MeshNode* nToRemove = *nIt;
7344       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7345       if ( nToRemove != nToKeep ) {
7346         //MESSAGE("  node to remove " << nToRemove->GetID());
7347         rmNodeIds.push_back( nToRemove->GetID() );
7348         AddToSameGroups( nToKeep, nToRemove, aMesh );
7349         // set _alwaysComputed to a sub-mesh of VERTEX to enable mesh computing
7350         // after MergeNodes() w/o creating node in place of merged ones.
7351         const SMDS_PositionPtr& pos = nToRemove->GetPosition();
7352         if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX )
7353           if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() ))
7354             sm->SetIsAlwaysComputed( true );
7355       }
7356
7357       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7358       while ( invElemIt->more() ) {
7359         const SMDS_MeshElement* elem = invElemIt->next();
7360         elems.insert(elem);
7361       }
7362     }
7363   }
7364   // Change element nodes or remove an element
7365
7366   set<const SMDS_MeshNode*> nodeSet;
7367   vector< const SMDS_MeshNode*> curNodes, uniqueNodes;
7368   vector<int> iRepl;
7369   ElemFeatures elemType;
7370
7371   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7372   for ( ; eIt != elems.end(); eIt++ )
7373   {
7374     const SMDS_MeshElement* elem = *eIt;
7375     int nbNodes = elem->NbNodes();
7376     int aShapeId = FindShape( elem );
7377
7378     nodeSet.clear();
7379     curNodes.resize( nbNodes );
7380     uniqueNodes.resize( nbNodes );
7381     iRepl.resize( nbNodes );
7382     int iUnique = 0, iCur = 0, nbRepl = 0;
7383
7384     // get new seq of nodes
7385     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7386     while ( itN->more() )
7387     {
7388       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( itN->next() );
7389
7390       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7391       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7392         n = (*nnIt).second;
7393         { ////////// BUG 0020185: begin
7394           bool stopRecur = false;
7395           set<const SMDS_MeshNode*> nodesRecur;
7396           nodesRecur.insert(n);
7397           while (!stopRecur) {
7398             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7399             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7400               n = (*nnIt_i).second;
7401               if (!nodesRecur.insert(n).second) {
7402                 // error: recursive dependancy
7403                 stopRecur = true;
7404               }
7405             }
7406             else
7407               stopRecur = true;
7408           }
7409         } ////////// BUG 0020185: end
7410       }
7411       curNodes[ iCur ] = n;
7412       bool isUnique = nodeSet.insert( n ).second;
7413       if ( isUnique )
7414         uniqueNodes[ iUnique++ ] = n;
7415       else
7416         iRepl[ nbRepl++ ] = iCur;
7417       iCur++;
7418     }
7419
7420     // Analyse element topology after replacement
7421
7422     bool isOk = true;
7423     int nbUniqueNodes = nodeSet.size();
7424     if ( nbNodes != nbUniqueNodes ) // some nodes stick
7425     {
7426       if (elem->IsPoly()) // Polygons and Polyhedral volumes
7427       {
7428         if (elem->GetType() == SMDSAbs_Face) // Polygon
7429         {
7430           elemType.Init( elem );
7431           const bool isQuad = elemType.myIsQuad;
7432           if ( isQuad )
7433             SMDS_MeshCell::applyInterlace // interlace medium and corner nodes
7434               ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, nbNodes ), curNodes );
7435
7436           // a polygon can divide into several elements
7437           vector<const SMDS_MeshNode *> polygons_nodes;
7438           vector<int> quantities;
7439           int nbNew = SimplifyFace( curNodes, polygons_nodes, quantities );
7440           if (nbNew > 0)
7441           {
7442             vector<const SMDS_MeshNode *> face_nodes;
7443             int inode = 0;
7444             for (int iface = 0; iface < nbNew; iface++)
7445             {
7446               int nbNewNodes = quantities[iface];
7447               face_nodes.assign( polygons_nodes.begin() + inode,
7448                                  polygons_nodes.begin() + inode + nbNewNodes );
7449               inode += nbNewNodes;
7450               if ( isQuad ) // check if a result elem is a valid quadratic polygon
7451               {
7452                 bool isValid = ( nbNewNodes % 2 == 0 );
7453                 for ( int i = 0; i < nbNewNodes && isValid; ++i )
7454                   isValid = ( elem->IsMediumNode( face_nodes[i]) == bool( i % 2 ));
7455                 elemType.SetQuad( isValid );
7456                 if ( isValid ) // put medium nodes after corners
7457                   SMDS_MeshCell::applyInterlaceRev
7458                     ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon,
7459                                                           nbNewNodes ), face_nodes );
7460               }
7461               SMDS_MeshElement* newElem = AddElement( face_nodes, elemType );
7462               if ( aShapeId )
7463                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7464             }
7465           }
7466           rmElemIds.push_back(elem->GetID());
7467
7468         } // Polygon
7469
7470         else if (elem->GetType() == SMDSAbs_Volume) // Polyhedral volume
7471         {
7472           if (nbUniqueNodes < 4) {
7473             rmElemIds.push_back(elem->GetID());
7474           }
7475           else {
7476             // each face has to be analyzed in order to check volume validity
7477             const SMDS_VtkVolume* aPolyedre =
7478               dynamic_cast<const SMDS_VtkVolume*>( elem );
7479             if (aPolyedre) {
7480               int nbFaces = aPolyedre->NbFaces();
7481
7482               vector<const SMDS_MeshNode *> poly_nodes;
7483               vector<int> quantities;
7484
7485               for (int iface = 1; iface <= nbFaces; iface++) {
7486                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7487                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7488
7489                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7490                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7491                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7492                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7493                     faceNode = (*nnIt).second;
7494                   }
7495                   faceNodes[inode - 1] = faceNode;
7496                 }
7497
7498                 SimplifyFace(faceNodes, poly_nodes, quantities);
7499               }
7500
7501               if (quantities.size() > 3) {
7502                 // to be done: remove coincident faces
7503               }
7504
7505               if (quantities.size() > 3)
7506               {
7507                 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7508                 const SMDS_MeshElement* newElem =
7509                   aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7510                 myLastCreatedElems.Append(newElem);
7511                 if ( aShapeId && newElem )
7512                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7513                 rmElemIds.push_back(elem->GetID());
7514               }
7515             }
7516             else {
7517               rmElemIds.push_back(elem->GetID());
7518             }
7519           }
7520         }
7521         else {
7522         }
7523
7524         continue;
7525       } // poly element
7526
7527       // Regular elements
7528       // TODO not all the possible cases are solved. Find something more generic?
7529       switch ( nbNodes ) {
7530       case 2: ///////////////////////////////////// EDGE
7531         isOk = false; break;
7532       case 3: ///////////////////////////////////// TRIANGLE
7533         isOk = false; break;
7534       case 4:
7535         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7536           isOk = false;
7537         else { //////////////////////////////////// QUADRANGLE
7538           if ( nbUniqueNodes < 3 )
7539             isOk = false;
7540           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7541             isOk = false; // opposite nodes stick
7542           //MESSAGE("isOk " << isOk);
7543         }
7544         break;
7545       case 6: ///////////////////////////////////// PENTAHEDRON
7546         if ( nbUniqueNodes == 4 ) {
7547           // ---------------------------------> tetrahedron
7548           if (nbRepl == 3 &&
7549               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7550             // all top nodes stick: reverse a bottom
7551             uniqueNodes[ 0 ] = curNodes [ 1 ];
7552             uniqueNodes[ 1 ] = curNodes [ 0 ];
7553           }
7554           else if (nbRepl == 3 &&
7555                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7556             // all bottom nodes stick: set a top before
7557             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7558             uniqueNodes[ 0 ] = curNodes [ 3 ];
7559             uniqueNodes[ 1 ] = curNodes [ 4 ];
7560             uniqueNodes[ 2 ] = curNodes [ 5 ];
7561           }
7562           else if (nbRepl == 4 &&
7563                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7564             // a lateral face turns into a line: reverse a bottom
7565             uniqueNodes[ 0 ] = curNodes [ 1 ];
7566             uniqueNodes[ 1 ] = curNodes [ 0 ];
7567           }
7568           else
7569             isOk = false;
7570         }
7571         else if ( nbUniqueNodes == 5 ) {
7572           // PENTAHEDRON --------------------> 2 tetrahedrons
7573           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7574             // a bottom node sticks with a linked top one
7575             // 1.
7576             SMDS_MeshElement* newElem =
7577               aMesh->AddVolume(curNodes[ 3 ],
7578                                curNodes[ 4 ],
7579                                curNodes[ 5 ],
7580                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7581             myLastCreatedElems.Append(newElem);
7582             if ( aShapeId )
7583               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7584             // 2. : reverse a bottom
7585             uniqueNodes[ 0 ] = curNodes [ 1 ];
7586             uniqueNodes[ 1 ] = curNodes [ 0 ];
7587             nbUniqueNodes = 4;
7588           }
7589           else
7590             isOk = false;
7591         }
7592         else
7593           isOk = false;
7594         break;
7595       case 8: {
7596         if(elem->IsQuadratic()) { // Quadratic quadrangle
7597           //   1    5    2
7598           //    +---+---+
7599           //    |       |
7600           //    |       |
7601           //   4+       +6
7602           //    |       |
7603           //    |       |
7604           //    +---+---+
7605           //   0    7    3
7606           isOk = false;
7607           if(nbRepl==2) {
7608             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7609           }
7610           if(nbRepl==3) {
7611             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7612             nbUniqueNodes = 6;
7613             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7614               uniqueNodes[0] = curNodes[0];
7615               uniqueNodes[1] = curNodes[2];
7616               uniqueNodes[2] = curNodes[3];
7617               uniqueNodes[3] = curNodes[5];
7618               uniqueNodes[4] = curNodes[6];
7619               uniqueNodes[5] = curNodes[7];
7620               isOk = true;
7621             }
7622             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7623               uniqueNodes[0] = curNodes[0];
7624               uniqueNodes[1] = curNodes[1];
7625               uniqueNodes[2] = curNodes[2];
7626               uniqueNodes[3] = curNodes[4];
7627               uniqueNodes[4] = curNodes[5];
7628               uniqueNodes[5] = curNodes[6];
7629               isOk = true;
7630             }
7631             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7632               uniqueNodes[0] = curNodes[1];
7633               uniqueNodes[1] = curNodes[2];
7634               uniqueNodes[2] = curNodes[3];
7635               uniqueNodes[3] = curNodes[5];
7636               uniqueNodes[4] = curNodes[6];
7637               uniqueNodes[5] = curNodes[0];
7638               isOk = true;
7639             }
7640             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7641               uniqueNodes[0] = curNodes[0];
7642               uniqueNodes[1] = curNodes[1];
7643               uniqueNodes[2] = curNodes[3];
7644               uniqueNodes[3] = curNodes[4];
7645               uniqueNodes[4] = curNodes[6];
7646               uniqueNodes[5] = curNodes[7];
7647               isOk = true;
7648             }
7649             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7650               uniqueNodes[0] = curNodes[0];
7651               uniqueNodes[1] = curNodes[2];
7652               uniqueNodes[2] = curNodes[3];
7653               uniqueNodes[3] = curNodes[1];
7654               uniqueNodes[4] = curNodes[6];
7655               uniqueNodes[5] = curNodes[7];
7656               isOk = true;
7657             }
7658             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7659               uniqueNodes[0] = curNodes[0];
7660               uniqueNodes[1] = curNodes[1];
7661               uniqueNodes[2] = curNodes[2];
7662               uniqueNodes[3] = curNodes[4];
7663               uniqueNodes[4] = curNodes[5];
7664               uniqueNodes[5] = curNodes[7];
7665               isOk = true;
7666             }
7667             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7668               uniqueNodes[0] = curNodes[0];
7669               uniqueNodes[1] = curNodes[1];
7670               uniqueNodes[2] = curNodes[3];
7671               uniqueNodes[3] = curNodes[4];
7672               uniqueNodes[4] = curNodes[2];
7673               uniqueNodes[5] = curNodes[7];
7674               isOk = true;
7675             }
7676             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7677               uniqueNodes[0] = curNodes[0];
7678               uniqueNodes[1] = curNodes[1];
7679               uniqueNodes[2] = curNodes[2];
7680               uniqueNodes[3] = curNodes[4];
7681               uniqueNodes[4] = curNodes[5];
7682               uniqueNodes[5] = curNodes[3];
7683               isOk = true;
7684             }
7685           }
7686           if(nbRepl==4) {
7687             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7688           }
7689           if(nbRepl==5) {
7690             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7691           }
7692           break;
7693         }
7694         //////////////////////////////////// HEXAHEDRON
7695         isOk = false;
7696         SMDS_VolumeTool hexa (elem);
7697         hexa.SetExternalNormal();
7698         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7699           //////////////////////// HEX ---> 1 tetrahedron
7700           for ( int iFace = 0; iFace < 6; iFace++ ) {
7701             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7702             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7703                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7704                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7705               // one face turns into a point ...
7706               int iOppFace = hexa.GetOppFaceIndex( iFace );
7707               ind = hexa.GetFaceNodesIndices( iOppFace );
7708               int nbStick = 0;
7709               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7710                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7711                   nbStick++;
7712               }
7713               if ( nbStick == 1 ) {
7714                 // ... and the opposite one - into a triangle.
7715                 // set a top node
7716                 ind = hexa.GetFaceNodesIndices( iFace );
7717                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7718                 isOk = true;
7719               }
7720               break;
7721             }
7722           }
7723         }
7724         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7725           //////////////////////// HEX ---> 1 prism
7726           int nbTria = 0, iTria[3];
7727           const int *ind; // indices of face nodes
7728           // look for triangular faces
7729           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7730             ind = hexa.GetFaceNodesIndices( iFace );
7731             TIDSortedNodeSet faceNodes;
7732             for ( iCur = 0; iCur < 4; iCur++ )
7733               faceNodes.insert( curNodes[ind[iCur]] );
7734             if ( faceNodes.size() == 3 )
7735               iTria[ nbTria++ ] = iFace;
7736           }
7737           // check if triangles are opposite
7738           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7739           {
7740             isOk = true;
7741             // set nodes of the bottom triangle
7742             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7743             vector<int> indB;
7744             for ( iCur = 0; iCur < 4; iCur++ )
7745               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7746                 indB.push_back( ind[iCur] );
7747             if ( !hexa.IsForward() )
7748               std::swap( indB[0], indB[2] );
7749             for ( iCur = 0; iCur < 3; iCur++ )
7750               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7751             // set nodes of the top triangle
7752             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7753             for ( iCur = 0; iCur < 3; ++iCur )
7754               for ( int j = 0; j < 4; ++j )
7755                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7756                 {
7757                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7758                   break;
7759                 }
7760           }
7761           break;
7762         }
7763         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7764           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7765           for ( int iFace = 0; iFace < 6; iFace++ ) {
7766             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7767             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7768                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7769                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7770               // one face turns into a point ...
7771               int iOppFace = hexa.GetOppFaceIndex( iFace );
7772               ind = hexa.GetFaceNodesIndices( iOppFace );
7773               int nbStick = 0;
7774               iUnique = 2;  // reverse a tetrahedron 1 bottom
7775               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7776                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7777                   nbStick++;
7778                 else if ( iUnique >= 0 )
7779                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7780               }
7781               if ( nbStick == 0 ) {
7782                 // ... and the opposite one is a quadrangle
7783                 // set a top node
7784                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7785                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7786                 nbUniqueNodes = 4;
7787                 // tetrahedron 2
7788                 SMDS_MeshElement* newElem =
7789                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7790                                    curNodes[ind[ 3 ]],
7791                                    curNodes[ind[ 2 ]],
7792                                    curNodes[indTop[ 0 ]]);
7793                 myLastCreatedElems.Append(newElem);
7794                 if ( aShapeId )
7795                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7796                 isOk = true;
7797               }
7798               break;
7799             }
7800           }
7801         }
7802         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7803           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7804           // find indices of quad and tri faces
7805           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7806           for ( iFace = 0; iFace < 6; iFace++ ) {
7807             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7808             nodeSet.clear();
7809             for ( iCur = 0; iCur < 4; iCur++ )
7810               nodeSet.insert( curNodes[ind[ iCur ]] );
7811             nbUniqueNodes = nodeSet.size();
7812             if ( nbUniqueNodes == 3 )
7813               iTriFace[ nbTri++ ] = iFace;
7814             else if ( nbUniqueNodes == 4 )
7815               iQuadFace[ nbQuad++ ] = iFace;
7816           }
7817           if (nbQuad == 2 && nbTri == 4 &&
7818               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7819             // 2 opposite quadrangles stuck with a diagonal;
7820             // sample groups of merged indices: (0-4)(2-6)
7821             // --------------------------------------------> 2 tetrahedrons
7822             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7823             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7824             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7825             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7826                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7827               // stuck with 0-2 diagonal
7828               i0  = ind1[ 3 ];
7829               i1d = ind1[ 0 ];
7830               i2  = ind1[ 1 ];
7831               i3d = ind1[ 2 ];
7832               i0t = ind2[ 1 ];
7833               i2t = ind2[ 3 ];
7834             }
7835             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7836                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7837               // stuck with 1-3 diagonal
7838               i0  = ind1[ 0 ];
7839               i1d = ind1[ 1 ];
7840               i2  = ind1[ 2 ];
7841               i3d = ind1[ 3 ];
7842               i0t = ind2[ 0 ];
7843               i2t = ind2[ 1 ];
7844             }
7845             else {
7846               ASSERT(0);
7847             }
7848             // tetrahedron 1
7849             uniqueNodes[ 0 ] = curNodes [ i0 ];
7850             uniqueNodes[ 1 ] = curNodes [ i1d ];
7851             uniqueNodes[ 2 ] = curNodes [ i3d ];
7852             uniqueNodes[ 3 ] = curNodes [ i0t ];
7853             nbUniqueNodes = 4;
7854             // tetrahedron 2
7855             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7856                                                          curNodes[ i2 ],
7857                                                          curNodes[ i3d ],
7858                                                          curNodes[ i2t ]);
7859             myLastCreatedElems.Append(newElem);
7860             if ( aShapeId )
7861               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7862             isOk = true;
7863           }
7864           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7865                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7866             // --------------------------------------------> prism
7867             // find 2 opposite triangles
7868             nbUniqueNodes = 6;
7869             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7870               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7871                 // find indices of kept and replaced nodes
7872                 // and fill unique nodes of 2 opposite triangles
7873                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7874                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7875                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7876                 // fill unique nodes
7877                 iUnique = 0;
7878                 isOk = true;
7879                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7880                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7881                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7882                   if ( n == nInit ) {
7883                     // iCur of a linked node of the opposite face (make normals co-directed):
7884                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7885                     // check that correspondent corners of triangles are linked
7886                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7887                       isOk = false;
7888                     else {
7889                       uniqueNodes[ iUnique ] = n;
7890                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7891                       iUnique++;
7892                     }
7893                   }
7894                 }
7895                 break;
7896               }
7897             }
7898           }
7899         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7900         else
7901         {
7902           MESSAGE("MergeNodes() removes hexahedron "<< elem);
7903         }
7904         break;
7905       } // HEXAHEDRON
7906
7907       default:
7908         isOk = false;
7909       } // switch ( nbNodes )
7910
7911     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7912
7913     if ( isOk ) // the non-poly elem remains valid after sticking nodes
7914     {
7915       elemType.Init( elem ).SetID( elem->GetID() );
7916
7917       SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
7918       aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7919
7920       uniqueNodes.resize(nbUniqueNodes);
7921       SMDS_MeshElement* newElem = this->AddElement( uniqueNodes, elemType );
7922       if ( sm && newElem )
7923         sm->AddElement( newElem );
7924       if ( elem != newElem )
7925         ReplaceElemInGroups( elem, newElem, aMesh );
7926     }
7927     else {
7928       // Remove invalid regular element or invalid polygon
7929       rmElemIds.push_back( elem->GetID() );
7930     }
7931
7932   } // loop on elements
7933
7934   // Remove bad elements, then equal nodes (order important)
7935
7936   Remove( rmElemIds, false );
7937   Remove( rmNodeIds, true );
7938
7939   return;
7940 }
7941
7942
7943 // ========================================================
7944 // class   : SortableElement
7945 // purpose : allow sorting elements basing on their nodes
7946 // ========================================================
7947 class SortableElement : public set <const SMDS_MeshElement*>
7948 {
7949 public:
7950
7951   SortableElement( const SMDS_MeshElement* theElem )
7952   {
7953     myElem = theElem;
7954     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7955     while ( nodeIt->more() )
7956       this->insert( nodeIt->next() );
7957   }
7958
7959   const SMDS_MeshElement* Get() const
7960   { return myElem; }
7961
7962   void Set(const SMDS_MeshElement* e) const
7963   { myElem = e; }
7964
7965
7966 private:
7967   mutable const SMDS_MeshElement* myElem;
7968 };
7969
7970 //=======================================================================
7971 //function : FindEqualElements
7972 //purpose  : Return list of group of elements built on the same nodes.
7973 //           Search among theElements or in the whole mesh if theElements is empty
7974 //=======================================================================
7975
7976 void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet &        theElements,
7977                                          TListOfListOfElementsID & theGroupsOfElementsID)
7978 {
7979   myLastCreatedElems.Clear();
7980   myLastCreatedNodes.Clear();
7981
7982   typedef map< SortableElement, int > TMapOfNodeSet;
7983   typedef list<int> TGroupOfElems;
7984
7985   if ( theElements.empty() )
7986   { // get all elements in the mesh
7987     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7988     while ( eIt->more() )
7989       theElements.insert( theElements.end(), eIt->next() );
7990   }
7991
7992   vector< TGroupOfElems > arrayOfGroups;
7993   TGroupOfElems groupOfElems;
7994   TMapOfNodeSet mapOfNodeSet;
7995
7996   TIDSortedElemSet::iterator elemIt = theElements.begin();
7997   for ( int i = 0; elemIt != theElements.end(); ++elemIt )
7998   {
7999     const SMDS_MeshElement* curElem = *elemIt;
8000     SortableElement SE(curElem);
8001     // check uniqueness
8002     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
8003     if ( !pp.second ) { // one more coincident elem
8004       TMapOfNodeSet::iterator& itSE = pp.first;
8005       int ind = (*itSE).second;
8006       arrayOfGroups[ind].push_back( curElem->GetID() );
8007     }
8008     else {
8009       arrayOfGroups.push_back( groupOfElems );
8010       arrayOfGroups.back().push_back( curElem->GetID() );
8011       i++;
8012     }
8013   }
8014
8015   groupOfElems.clear();
8016   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
8017   for ( ; groupIt != arrayOfGroups.end(); ++groupIt )
8018   {
8019     if ( groupIt->size() > 1 ) {
8020       //groupOfElems.sort(); -- theElements is sorted already
8021       theGroupsOfElementsID.push_back( groupOfElems );
8022       theGroupsOfElementsID.back().splice( theGroupsOfElementsID.back().end(), *groupIt );
8023     }
8024   }
8025 }
8026
8027 //=======================================================================
8028 //function : MergeElements
8029 //purpose  : In each given group, substitute all elements by the first one.
8030 //=======================================================================
8031
8032 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8033 {
8034   myLastCreatedElems.Clear();
8035   myLastCreatedNodes.Clear();
8036
8037   typedef list<int> TListOfIDs;
8038   TListOfIDs rmElemIds; // IDs of elems to remove
8039
8040   SMESHDS_Mesh* aMesh = GetMeshDS();
8041
8042   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8043   while ( groupsIt != theGroupsOfElementsID.end() ) {
8044     TListOfIDs& aGroupOfElemID = *groupsIt;
8045     aGroupOfElemID.sort();
8046     int elemIDToKeep = aGroupOfElemID.front();
8047     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8048     aGroupOfElemID.pop_front();
8049     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8050     while ( idIt != aGroupOfElemID.end() ) {
8051       int elemIDToRemove = *idIt;
8052       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8053       // add the kept element in groups of removed one (PAL15188)
8054       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8055       rmElemIds.push_back( elemIDToRemove );
8056       ++idIt;
8057     }
8058     ++groupsIt;
8059   }
8060
8061   Remove( rmElemIds, false );
8062 }
8063
8064 //=======================================================================
8065 //function : MergeEqualElements
8066 //purpose  : Remove all but one of elements built on the same nodes.
8067 //=======================================================================
8068
8069 void SMESH_MeshEditor::MergeEqualElements()
8070 {
8071   TIDSortedElemSet aMeshElements; /* empty input ==
8072                                      to merge equal elements in the whole mesh */
8073   TListOfListOfElementsID aGroupsOfElementsID;
8074   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8075   MergeElements(aGroupsOfElementsID);
8076 }
8077
8078 //=======================================================================
8079 //function : findAdjacentFace
8080 //purpose  :
8081 //=======================================================================
8082
8083 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8084                                                 const SMDS_MeshNode* n2,
8085                                                 const SMDS_MeshElement* elem)
8086 {
8087   TIDSortedElemSet elemSet, avoidSet;
8088   if ( elem )
8089     avoidSet.insert ( elem );
8090   return SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet );
8091 }
8092
8093 //=======================================================================
8094 //function : FindFreeBorder
8095 //purpose  :
8096 //=======================================================================
8097
8098 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8099
8100 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8101                                        const SMDS_MeshNode*             theSecondNode,
8102                                        const SMDS_MeshNode*             theLastNode,
8103                                        list< const SMDS_MeshNode* > &   theNodes,
8104                                        list< const SMDS_MeshElement* >& theFaces)
8105 {
8106   if ( !theFirstNode || !theSecondNode )
8107     return false;
8108   // find border face between theFirstNode and theSecondNode
8109   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8110   if ( !curElem )
8111     return false;
8112
8113   theFaces.push_back( curElem );
8114   theNodes.push_back( theFirstNode );
8115   theNodes.push_back( theSecondNode );
8116
8117   //vector<const SMDS_MeshNode*> nodes;
8118   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8119   TIDSortedElemSet foundElems;
8120   bool needTheLast = ( theLastNode != 0 );
8121
8122   while ( nStart != theLastNode ) {
8123     if ( nStart == theFirstNode )
8124       return !needTheLast;
8125
8126     // find all free border faces sharing form nStart
8127
8128     list< const SMDS_MeshElement* > curElemList;
8129     list< const SMDS_MeshNode* > nStartList;
8130     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8131     while ( invElemIt->more() ) {
8132       const SMDS_MeshElement* e = invElemIt->next();
8133       if ( e == curElem || foundElems.insert( e ).second ) {
8134         // get nodes
8135         int iNode = 0, nbNodes = e->NbNodes();
8136         //const SMDS_MeshNode* nodes[nbNodes+1];
8137         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8138
8139         if(e->IsQuadratic()) {
8140           const SMDS_VtkFace* F =
8141             dynamic_cast<const SMDS_VtkFace*>(e);
8142           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8143           // use special nodes iterator
8144           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8145           while( anIter->more() ) {
8146             nodes[ iNode++ ] = cast2Node(anIter->next());
8147           }
8148         }
8149         else {
8150           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8151           while ( nIt->more() )
8152             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8153         }
8154         nodes[ iNode ] = nodes[ 0 ];
8155         // check 2 links
8156         for ( iNode = 0; iNode < nbNodes; iNode++ )
8157           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8158                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8159               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8160           {
8161             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8162             curElemList.push_back( e );
8163           }
8164       }
8165     }
8166     // analyse the found
8167
8168     int nbNewBorders = curElemList.size();
8169     if ( nbNewBorders == 0 ) {
8170       // no free border furthermore
8171       return !needTheLast;
8172     }
8173     else if ( nbNewBorders == 1 ) {
8174       // one more element found
8175       nIgnore = nStart;
8176       nStart = nStartList.front();
8177       curElem = curElemList.front();
8178       theFaces.push_back( curElem );
8179       theNodes.push_back( nStart );
8180     }
8181     else {
8182       // several continuations found
8183       list< const SMDS_MeshElement* >::iterator curElemIt;
8184       list< const SMDS_MeshNode* >::iterator nStartIt;
8185       // check if one of them reached the last node
8186       if ( needTheLast ) {
8187         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8188              curElemIt!= curElemList.end();
8189              curElemIt++, nStartIt++ )
8190           if ( *nStartIt == theLastNode ) {
8191             theFaces.push_back( *curElemIt );
8192             theNodes.push_back( *nStartIt );
8193             return true;
8194           }
8195       }
8196       // find the best free border by the continuations
8197       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8198       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8199       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8200            curElemIt!= curElemList.end();
8201            curElemIt++, nStartIt++ )
8202       {
8203         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8204         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8205         // find one more free border
8206         if ( ! SMESH_MeshEditor::FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8207           cNL->clear();
8208           cFL->clear();
8209         }
8210         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8211           // choice: clear a worse one
8212           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8213           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8214           contNodes[ iWorse ].clear();
8215           contFaces[ iWorse ].clear();
8216         }
8217       }
8218       if ( contNodes[0].empty() && contNodes[1].empty() )
8219         return false;
8220
8221       // append the best free border
8222       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8223       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8224       theNodes.pop_back(); // remove nIgnore
8225       theNodes.pop_back(); // remove nStart
8226       theFaces.pop_back(); // remove curElem
8227       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8228       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8229       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8230       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8231       return true;
8232
8233     } // several continuations found
8234   } // while ( nStart != theLastNode )
8235
8236   return true;
8237 }
8238
8239 //=======================================================================
8240 //function : CheckFreeBorderNodes
8241 //purpose  : Return true if the tree nodes are on a free border
8242 //=======================================================================
8243
8244 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8245                                             const SMDS_MeshNode* theNode2,
8246                                             const SMDS_MeshNode* theNode3)
8247 {
8248   list< const SMDS_MeshNode* > nodes;
8249   list< const SMDS_MeshElement* > faces;
8250   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8251 }
8252
8253 //=======================================================================
8254 //function : SewFreeBorder
8255 //purpose  :
8256 //=======================================================================
8257
8258 SMESH_MeshEditor::Sew_Error
8259 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8260                                  const SMDS_MeshNode* theBordSecondNode,
8261                                  const SMDS_MeshNode* theBordLastNode,
8262                                  const SMDS_MeshNode* theSideFirstNode,
8263                                  const SMDS_MeshNode* theSideSecondNode,
8264                                  const SMDS_MeshNode* theSideThirdNode,
8265                                  const bool           theSideIsFreeBorder,
8266                                  const bool           toCreatePolygons,
8267                                  const bool           toCreatePolyedrs)
8268 {
8269   myLastCreatedElems.Clear();
8270   myLastCreatedNodes.Clear();
8271
8272   MESSAGE("::SewFreeBorder()");
8273   Sew_Error aResult = SEW_OK;
8274
8275   // ====================================
8276   //    find side nodes and elements
8277   // ====================================
8278
8279   list< const SMDS_MeshNode* > nSide[ 2 ];
8280   list< const SMDS_MeshElement* > eSide[ 2 ];
8281   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8282   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8283
8284   // Free border 1
8285   // --------------
8286   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8287                       nSide[0], eSide[0])) {
8288     MESSAGE(" Free Border 1 not found " );
8289     aResult = SEW_BORDER1_NOT_FOUND;
8290   }
8291   if (theSideIsFreeBorder) {
8292     // Free border 2
8293     // --------------
8294     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8295                         nSide[1], eSide[1])) {
8296       MESSAGE(" Free Border 2 not found " );
8297       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8298     }
8299   }
8300   if ( aResult != SEW_OK )
8301     return aResult;
8302
8303   if (!theSideIsFreeBorder) {
8304     // Side 2
8305     // --------------
8306
8307     // -------------------------------------------------------------------------
8308     // Algo:
8309     // 1. If nodes to merge are not coincident, move nodes of the free border
8310     //    from the coord sys defined by the direction from the first to last
8311     //    nodes of the border to the correspondent sys of the side 2
8312     // 2. On the side 2, find the links most co-directed with the correspondent
8313     //    links of the free border
8314     // -------------------------------------------------------------------------
8315
8316     // 1. Since sewing may break if there are volumes to split on the side 2,
8317     //    we wont move nodes but just compute new coordinates for them
8318     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8319     TNodeXYZMap nBordXYZ;
8320     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8321     list< const SMDS_MeshNode* >::iterator nBordIt;
8322
8323     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8324     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8325     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8326     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8327     double tol2 = 1.e-8;
8328     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8329     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8330       // Need node movement.
8331
8332       // find X and Z axes to create trsf
8333       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8334       gp_Vec X = Zs ^ Zb;
8335       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8336         // Zb || Zs
8337         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8338
8339       // coord systems
8340       gp_Ax3 toBordAx( Pb1, Zb, X );
8341       gp_Ax3 fromSideAx( Ps1, Zs, X );
8342       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8343       // set trsf
8344       gp_Trsf toBordSys, fromSide2Sys;
8345       toBordSys.SetTransformation( toBordAx );
8346       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8347       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8348
8349       // move
8350       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8351         const SMDS_MeshNode* n = *nBordIt;
8352         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8353         toBordSys.Transforms( xyz );
8354         fromSide2Sys.Transforms( xyz );
8355         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8356       }
8357     }
8358     else {
8359       // just insert nodes XYZ in the nBordXYZ map
8360       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8361         const SMDS_MeshNode* n = *nBordIt;
8362         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8363       }
8364     }
8365
8366     // 2. On the side 2, find the links most co-directed with the correspondent
8367     //    links of the free border
8368
8369     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8370     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8371     sideNodes.push_back( theSideFirstNode );
8372
8373     bool hasVolumes = false;
8374     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8375     set<long> foundSideLinkIDs, checkedLinkIDs;
8376     SMDS_VolumeTool volume;
8377     //const SMDS_MeshNode* faceNodes[ 4 ];
8378
8379     const SMDS_MeshNode*    sideNode;
8380     const SMDS_MeshElement* sideElem;
8381     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8382     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8383     nBordIt = bordNodes.begin();
8384     nBordIt++;
8385     // border node position and border link direction to compare with
8386     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8387     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8388     // choose next side node by link direction or by closeness to
8389     // the current border node:
8390     bool searchByDir = ( *nBordIt != theBordLastNode );
8391     do {
8392       // find the next node on the Side 2
8393       sideNode = 0;
8394       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8395       long linkID;
8396       checkedLinkIDs.clear();
8397       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8398
8399       // loop on inverse elements of current node (prevSideNode) on the Side 2
8400       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8401       while ( invElemIt->more() )
8402       {
8403         const SMDS_MeshElement* elem = invElemIt->next();
8404         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8405         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8406         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8407         bool isVolume = volume.Set( elem );
8408         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8409         if ( isVolume ) // --volume
8410           hasVolumes = true;
8411         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8412           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8413           if(elem->IsQuadratic()) {
8414             const SMDS_VtkFace* F =
8415               dynamic_cast<const SMDS_VtkFace*>(elem);
8416             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8417             // use special nodes iterator
8418             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8419             while( anIter->more() ) {
8420               nodes[ iNode ] = cast2Node(anIter->next());
8421               if ( nodes[ iNode++ ] == prevSideNode )
8422                 iPrevNode = iNode - 1;
8423             }
8424           }
8425           else {
8426             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8427             while ( nIt->more() ) {
8428               nodes[ iNode ] = cast2Node( nIt->next() );
8429               if ( nodes[ iNode++ ] == prevSideNode )
8430                 iPrevNode = iNode - 1;
8431             }
8432           }
8433           // there are 2 links to check
8434           nbNodes = 2;
8435         }
8436         else // --edge
8437           continue;
8438         // loop on links, to be precise, on the second node of links
8439         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8440           const SMDS_MeshNode* n = nodes[ iNode ];
8441           if ( isVolume ) {
8442             if ( !volume.IsLinked( n, prevSideNode ))
8443               continue;
8444           }
8445           else {
8446             if ( iNode ) // a node before prevSideNode
8447               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8448             else         // a node after prevSideNode
8449               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8450           }
8451           // check if this link was already used
8452           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8453           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8454           if (!isJustChecked &&
8455               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8456           {
8457             // test a link geometrically
8458             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8459             bool linkIsBetter = false;
8460             double dot = 0.0, dist = 0.0;
8461             if ( searchByDir ) { // choose most co-directed link
8462               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8463               linkIsBetter = ( dot > maxDot );
8464             }
8465             else { // choose link with the node closest to bordPos
8466               dist = ( nextXYZ - bordPos ).SquareModulus();
8467               linkIsBetter = ( dist < minDist );
8468             }
8469             if ( linkIsBetter ) {
8470               maxDot = dot;
8471               minDist = dist;
8472               linkID = iLink;
8473               sideNode = n;
8474               sideElem = elem;
8475             }
8476           }
8477         }
8478       } // loop on inverse elements of prevSideNode
8479
8480       if ( !sideNode ) {
8481         MESSAGE(" Cant find path by links of the Side 2 ");
8482         return SEW_BAD_SIDE_NODES;
8483       }
8484       sideNodes.push_back( sideNode );
8485       sideElems.push_back( sideElem );
8486       foundSideLinkIDs.insert ( linkID );
8487       prevSideNode = sideNode;
8488
8489       if ( *nBordIt == theBordLastNode )
8490         searchByDir = false;
8491       else {
8492         // find the next border link to compare with
8493         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8494         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8495         // move to next border node if sideNode is before forward border node (bordPos)
8496         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8497           prevBordNode = *nBordIt;
8498           nBordIt++;
8499           bordPos = nBordXYZ[ *nBordIt ];
8500           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8501           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8502         }
8503       }
8504     }
8505     while ( sideNode != theSideSecondNode );
8506
8507     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8508       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8509       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8510     }
8511   } // end nodes search on the side 2
8512
8513   // ============================
8514   // sew the border to the side 2
8515   // ============================
8516
8517   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8518   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8519
8520   TListOfListOfNodes nodeGroupsToMerge;
8521   if ( nbNodes[0] == nbNodes[1] ||
8522        ( theSideIsFreeBorder && !theSideThirdNode)) {
8523
8524     // all nodes are to be merged
8525
8526     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8527          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8528          nIt[0]++, nIt[1]++ )
8529     {
8530       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8531       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8532       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8533     }
8534   }
8535   else {
8536
8537     // insert new nodes into the border and the side to get equal nb of segments
8538
8539     // get normalized parameters of nodes on the borders
8540     //double param[ 2 ][ maxNbNodes ];
8541     double* param[ 2 ];
8542     param[0] = new double [ maxNbNodes ];
8543     param[1] = new double [ maxNbNodes ];
8544     int iNode, iBord;
8545     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8546       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8547       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8548       const SMDS_MeshNode* nPrev = *nIt;
8549       double bordLength = 0;
8550       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8551         const SMDS_MeshNode* nCur = *nIt;
8552         gp_XYZ segment (nCur->X() - nPrev->X(),
8553                         nCur->Y() - nPrev->Y(),
8554                         nCur->Z() - nPrev->Z());
8555         double segmentLen = segment.Modulus();
8556         bordLength += segmentLen;
8557         param[ iBord ][ iNode ] = bordLength;
8558         nPrev = nCur;
8559       }
8560       // normalize within [0,1]
8561       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8562         param[ iBord ][ iNode ] /= bordLength;
8563       }
8564     }
8565
8566     // loop on border segments
8567     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8568     int i[ 2 ] = { 0, 0 };
8569     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8570     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8571
8572     TElemOfNodeListMap insertMap;
8573     TElemOfNodeListMap::iterator insertMapIt;
8574     // insertMap is
8575     // key:   elem to insert nodes into
8576     // value: 2 nodes to insert between + nodes to be inserted
8577     do {
8578       bool next[ 2 ] = { false, false };
8579
8580       // find min adjacent segment length after sewing
8581       double nextParam = 10., prevParam = 0;
8582       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8583         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8584           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8585         if ( i[ iBord ] > 0 )
8586           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8587       }
8588       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8589       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8590       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8591
8592       // choose to insert or to merge nodes
8593       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8594       if ( Abs( du ) <= minSegLen * 0.2 ) {
8595         // merge
8596         // ------
8597         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8598         const SMDS_MeshNode* n0 = *nIt[0];
8599         const SMDS_MeshNode* n1 = *nIt[1];
8600         nodeGroupsToMerge.back().push_back( n1 );
8601         nodeGroupsToMerge.back().push_back( n0 );
8602         // position of node of the border changes due to merge
8603         param[ 0 ][ i[0] ] += du;
8604         // move n1 for the sake of elem shape evaluation during insertion.
8605         // n1 will be removed by MergeNodes() anyway
8606         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8607         next[0] = next[1] = true;
8608       }
8609       else {
8610         // insert
8611         // ------
8612         int intoBord = ( du < 0 ) ? 0 : 1;
8613         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8614         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8615         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8616         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8617         if ( intoBord == 1 ) {
8618           // move node of the border to be on a link of elem of the side
8619           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8620           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8621           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8622           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8623           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8624         }
8625         insertMapIt = insertMap.find( elem );
8626         bool notFound = ( insertMapIt == insertMap.end() );
8627         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8628         if ( otherLink ) {
8629           // insert into another link of the same element:
8630           // 1. perform insertion into the other link of the elem
8631           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8632           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8633           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8634           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8635           // 2. perform insertion into the link of adjacent faces
8636           while (true) {
8637             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8638             if ( adjElem )
8639               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8640             else
8641               break;
8642           }
8643           if (toCreatePolyedrs) {
8644             // perform insertion into the links of adjacent volumes
8645             UpdateVolumes(n12, n22, nodeList);
8646           }
8647           // 3. find an element appeared on n1 and n2 after the insertion
8648           insertMap.erase( elem );
8649           elem = findAdjacentFace( n1, n2, 0 );
8650         }
8651         if ( notFound || otherLink ) {
8652           // add element and nodes of the side into the insertMap
8653           insertMapIt = insertMap.insert
8654             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8655           (*insertMapIt).second.push_back( n1 );
8656           (*insertMapIt).second.push_back( n2 );
8657         }
8658         // add node to be inserted into elem
8659         (*insertMapIt).second.push_back( nIns );
8660         next[ 1 - intoBord ] = true;
8661       }
8662
8663       // go to the next segment
8664       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8665         if ( next[ iBord ] ) {
8666           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8667             eIt[ iBord ]++;
8668           nPrev[ iBord ] = *nIt[ iBord ];
8669           nIt[ iBord ]++; i[ iBord ]++;
8670         }
8671       }
8672     }
8673     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8674
8675     // perform insertion of nodes into elements
8676
8677     for (insertMapIt = insertMap.begin();
8678          insertMapIt != insertMap.end();
8679          insertMapIt++ )
8680     {
8681       const SMDS_MeshElement* elem = (*insertMapIt).first;
8682       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8683       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8684       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8685
8686       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8687
8688       if ( !theSideIsFreeBorder ) {
8689         // look for and insert nodes into the faces adjacent to elem
8690         while (true) {
8691           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8692           if ( adjElem )
8693             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8694           else
8695             break;
8696         }
8697       }
8698       if (toCreatePolyedrs) {
8699         // perform insertion into the links of adjacent volumes
8700         UpdateVolumes(n1, n2, nodeList);
8701       }
8702     }
8703
8704     delete param[0];
8705     delete param[1];
8706   } // end: insert new nodes
8707
8708   MergeNodes ( nodeGroupsToMerge );
8709
8710   return aResult;
8711 }
8712
8713 //=======================================================================
8714 //function : InsertNodesIntoLink
8715 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8716 //           and theBetweenNode2 and split theElement
8717 //=======================================================================
8718
8719 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8720                                            const SMDS_MeshNode*        theBetweenNode1,
8721                                            const SMDS_MeshNode*        theBetweenNode2,
8722                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8723                                            const bool                  toCreatePoly)
8724 {
8725   if ( theFace->GetType() != SMDSAbs_Face ) return;
8726
8727   // find indices of 2 link nodes and of the rest nodes
8728   int iNode = 0, il1, il2, i3, i4;
8729   il1 = il2 = i3 = i4 = -1;
8730   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8731   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8732
8733   if(theFace->IsQuadratic()) {
8734     const SMDS_VtkFace* F =
8735       dynamic_cast<const SMDS_VtkFace*>(theFace);
8736     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8737     // use special nodes iterator
8738     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8739     while( anIter->more() ) {
8740       const SMDS_MeshNode* n = cast2Node(anIter->next());
8741       if ( n == theBetweenNode1 )
8742         il1 = iNode;
8743       else if ( n == theBetweenNode2 )
8744         il2 = iNode;
8745       else if ( i3 < 0 )
8746         i3 = iNode;
8747       else
8748         i4 = iNode;
8749       nodes[ iNode++ ] = n;
8750     }
8751   }
8752   else {
8753     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8754     while ( nodeIt->more() ) {
8755       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8756       if ( n == theBetweenNode1 )
8757         il1 = iNode;
8758       else if ( n == theBetweenNode2 )
8759         il2 = iNode;
8760       else if ( i3 < 0 )
8761         i3 = iNode;
8762       else
8763         i4 = iNode;
8764       nodes[ iNode++ ] = n;
8765     }
8766   }
8767   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8768     return ;
8769
8770   // arrange link nodes to go one after another regarding the face orientation
8771   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8772   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8773   if ( reverse ) {
8774     iNode = il1;
8775     il1 = il2;
8776     il2 = iNode;
8777     aNodesToInsert.reverse();
8778   }
8779   // check that not link nodes of a quadrangles are in good order
8780   int nbFaceNodes = theFace->NbNodes();
8781   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8782     iNode = i3;
8783     i3 = i4;
8784     i4 = iNode;
8785   }
8786
8787   if (toCreatePoly || theFace->IsPoly()) {
8788
8789     iNode = 0;
8790     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8791
8792     // add nodes of face up to first node of link
8793     bool isFLN = false;
8794
8795     if(theFace->IsQuadratic()) {
8796       const SMDS_VtkFace* F =
8797         dynamic_cast<const SMDS_VtkFace*>(theFace);
8798       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8799       // use special nodes iterator
8800       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8801       while( anIter->more()  && !isFLN ) {
8802         const SMDS_MeshNode* n = cast2Node(anIter->next());
8803         poly_nodes[iNode++] = n;
8804         if (n == nodes[il1]) {
8805           isFLN = true;
8806         }
8807       }
8808       // add nodes to insert
8809       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8810       for (; nIt != aNodesToInsert.end(); nIt++) {
8811         poly_nodes[iNode++] = *nIt;
8812       }
8813       // add nodes of face starting from last node of link
8814       while ( anIter->more() ) {
8815         poly_nodes[iNode++] = cast2Node(anIter->next());
8816       }
8817     }
8818     else {
8819       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8820       while ( nodeIt->more() && !isFLN ) {
8821         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8822         poly_nodes[iNode++] = n;
8823         if (n == nodes[il1]) {
8824           isFLN = true;
8825         }
8826       }
8827       // add nodes to insert
8828       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8829       for (; nIt != aNodesToInsert.end(); nIt++) {
8830         poly_nodes[iNode++] = *nIt;
8831       }
8832       // add nodes of face starting from last node of link
8833       while ( nodeIt->more() ) {
8834         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8835         poly_nodes[iNode++] = n;
8836       }
8837     }
8838
8839     // edit or replace the face
8840     SMESHDS_Mesh *aMesh = GetMeshDS();
8841
8842     if (theFace->IsPoly()) {
8843       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8844     }
8845     else {
8846       int aShapeId = FindShape( theFace );
8847
8848       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8849       myLastCreatedElems.Append(newElem);
8850       if ( aShapeId && newElem )
8851         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8852
8853       aMesh->RemoveElement(theFace);
8854     }
8855     return;
8856   }
8857
8858   SMESHDS_Mesh *aMesh = GetMeshDS();
8859   if( !theFace->IsQuadratic() ) {
8860
8861     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8862     int nbLinkNodes = 2 + aNodesToInsert.size();
8863     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8864     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8865     linkNodes[ 0 ] = nodes[ il1 ];
8866     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8867     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8868     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8869       linkNodes[ iNode++ ] = *nIt;
8870     }
8871     // decide how to split a quadrangle: compare possible variants
8872     // and choose which of splits to be a quadrangle
8873     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8874     if ( nbFaceNodes == 3 ) {
8875       iBestQuad = nbSplits;
8876       i4 = i3;
8877     }
8878     else if ( nbFaceNodes == 4 ) {
8879       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8880       double aBestRate = DBL_MAX;
8881       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8882         i1 = 0; i2 = 1;
8883         double aBadRate = 0;
8884         // evaluate elements quality
8885         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8886           if ( iSplit == iQuad ) {
8887             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8888                                    linkNodes[ i2++ ],
8889                                    nodes[ i3 ],
8890                                    nodes[ i4 ]);
8891             aBadRate += getBadRate( &quad, aCrit );
8892           }
8893           else {
8894             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8895                                    linkNodes[ i2++ ],
8896                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8897             aBadRate += getBadRate( &tria, aCrit );
8898           }
8899         }
8900         // choice
8901         if ( aBadRate < aBestRate ) {
8902           iBestQuad = iQuad;
8903           aBestRate = aBadRate;
8904         }
8905       }
8906     }
8907
8908     // create new elements
8909     int aShapeId = FindShape( theFace );
8910
8911     i1 = 0; i2 = 1;
8912     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8913       SMDS_MeshElement* newElem = 0;
8914       if ( iSplit == iBestQuad )
8915         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8916                                   linkNodes[ i2++ ],
8917                                   nodes[ i3 ],
8918                                   nodes[ i4 ]);
8919       else
8920         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8921                                   linkNodes[ i2++ ],
8922                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8923       myLastCreatedElems.Append(newElem);
8924       if ( aShapeId && newElem )
8925         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8926     }
8927
8928     // change nodes of theFace
8929     const SMDS_MeshNode* newNodes[ 4 ];
8930     newNodes[ 0 ] = linkNodes[ i1 ];
8931     newNodes[ 1 ] = linkNodes[ i2 ];
8932     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8933     newNodes[ 3 ] = nodes[ i4 ];
8934     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8935     const SMDS_MeshElement* newElem = 0;
8936     if (iSplit == iBestQuad)
8937       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8938     else
8939       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8940     myLastCreatedElems.Append(newElem);
8941     if ( aShapeId && newElem )
8942       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8943 } // end if(!theFace->IsQuadratic())
8944   else { // theFace is quadratic
8945     // we have to split theFace on simple triangles and one simple quadrangle
8946     int tmp = il1/2;
8947     int nbshift = tmp*2;
8948     // shift nodes in nodes[] by nbshift
8949     int i,j;
8950     for(i=0; i<nbshift; i++) {
8951       const SMDS_MeshNode* n = nodes[0];
8952       for(j=0; j<nbFaceNodes-1; j++) {
8953         nodes[j] = nodes[j+1];
8954       }
8955       nodes[nbFaceNodes-1] = n;
8956     }
8957     il1 = il1 - nbshift;
8958     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8959     //   n0      n1     n2    n0      n1     n2
8960     //     +-----+-----+        +-----+-----+
8961     //      \         /         |           |
8962     //       \       /          |           |
8963     //      n5+     +n3       n7+           +n3
8964     //         \   /            |           |
8965     //          \ /             |           |
8966     //           +              +-----+-----+
8967     //           n4           n6      n5     n4
8968
8969     // create new elements
8970     int aShapeId = FindShape( theFace );
8971
8972     int n1,n2,n3;
8973     if(nbFaceNodes==6) { // quadratic triangle
8974       SMDS_MeshElement* newElem =
8975         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8976       myLastCreatedElems.Append(newElem);
8977       if ( aShapeId && newElem )
8978         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8979       if(theFace->IsMediumNode(nodes[il1])) {
8980         // create quadrangle
8981         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8982         myLastCreatedElems.Append(newElem);
8983         if ( aShapeId && newElem )
8984           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8985         n1 = 1;
8986         n2 = 2;
8987         n3 = 3;
8988       }
8989       else {
8990         // create quadrangle
8991         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8992         myLastCreatedElems.Append(newElem);
8993         if ( aShapeId && newElem )
8994           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8995         n1 = 0;
8996         n2 = 1;
8997         n3 = 5;
8998       }
8999     }
9000     else { // nbFaceNodes==8 - quadratic quadrangle
9001       SMDS_MeshElement* newElem =
9002         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9003       myLastCreatedElems.Append(newElem);
9004       if ( aShapeId && newElem )
9005         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9006       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9007       myLastCreatedElems.Append(newElem);
9008       if ( aShapeId && newElem )
9009         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9010       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9011       myLastCreatedElems.Append(newElem);
9012       if ( aShapeId && newElem )
9013         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9014       if(theFace->IsMediumNode(nodes[il1])) {
9015         // create quadrangle
9016         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9017         myLastCreatedElems.Append(newElem);
9018         if ( aShapeId && newElem )
9019           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9020         n1 = 1;
9021         n2 = 2;
9022         n3 = 3;
9023       }
9024       else {
9025         // create quadrangle
9026         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9027         myLastCreatedElems.Append(newElem);
9028         if ( aShapeId && newElem )
9029           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9030         n1 = 0;
9031         n2 = 1;
9032         n3 = 7;
9033       }
9034     }
9035     // create needed triangles using n1,n2,n3 and inserted nodes
9036     int nbn = 2 + aNodesToInsert.size();
9037     //const SMDS_MeshNode* aNodes[nbn];
9038     vector<const SMDS_MeshNode*> aNodes(nbn);
9039     aNodes[0] = nodes[n1];
9040     aNodes[nbn-1] = nodes[n2];
9041     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9042     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9043       aNodes[iNode++] = *nIt;
9044     }
9045     for(i=1; i<nbn; i++) {
9046       SMDS_MeshElement* newElem =
9047         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9048       myLastCreatedElems.Append(newElem);
9049       if ( aShapeId && newElem )
9050         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9051     }
9052   }
9053   // remove old face
9054   aMesh->RemoveElement(theFace);
9055 }
9056
9057 //=======================================================================
9058 //function : UpdateVolumes
9059 //purpose  :
9060 //=======================================================================
9061 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9062                                       const SMDS_MeshNode*        theBetweenNode2,
9063                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9064 {
9065   myLastCreatedElems.Clear();
9066   myLastCreatedNodes.Clear();
9067
9068   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9069   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9070     const SMDS_MeshElement* elem = invElemIt->next();
9071
9072     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9073     SMDS_VolumeTool aVolume (elem);
9074     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9075       continue;
9076
9077     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9078     int iface, nbFaces = aVolume.NbFaces();
9079     vector<const SMDS_MeshNode *> poly_nodes;
9080     vector<int> quantities (nbFaces);
9081
9082     for (iface = 0; iface < nbFaces; iface++) {
9083       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9084       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9085       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9086
9087       for (int inode = 0; inode < nbFaceNodes; inode++) {
9088         poly_nodes.push_back(faceNodes[inode]);
9089
9090         if (nbInserted == 0) {
9091           if (faceNodes[inode] == theBetweenNode1) {
9092             if (faceNodes[inode + 1] == theBetweenNode2) {
9093               nbInserted = theNodesToInsert.size();
9094
9095               // add nodes to insert
9096               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9097               for (; nIt != theNodesToInsert.end(); nIt++) {
9098                 poly_nodes.push_back(*nIt);
9099               }
9100             }
9101           }
9102           else if (faceNodes[inode] == theBetweenNode2) {
9103             if (faceNodes[inode + 1] == theBetweenNode1) {
9104               nbInserted = theNodesToInsert.size();
9105
9106               // add nodes to insert in reversed order
9107               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9108               nIt--;
9109               for (; nIt != theNodesToInsert.begin(); nIt--) {
9110                 poly_nodes.push_back(*nIt);
9111               }
9112               poly_nodes.push_back(*nIt);
9113             }
9114           }
9115           else {
9116           }
9117         }
9118       }
9119       quantities[iface] = nbFaceNodes + nbInserted;
9120     }
9121
9122     // Replace or update the volume
9123     SMESHDS_Mesh *aMesh = GetMeshDS();
9124
9125     if (elem->IsPoly()) {
9126       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9127
9128     }
9129     else {
9130       int aShapeId = FindShape( elem );
9131
9132       SMDS_MeshElement* newElem =
9133         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9134       myLastCreatedElems.Append(newElem);
9135       if (aShapeId && newElem)
9136         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9137
9138       aMesh->RemoveElement(elem);
9139     }
9140   }
9141 }
9142
9143 namespace
9144 {
9145   //================================================================================
9146   /*!
9147    * \brief Transform any volume into data of SMDSEntity_Polyhedra
9148    */
9149   //================================================================================
9150
9151   void volumeToPolyhedron( const SMDS_MeshElement*         elem,
9152                            vector<const SMDS_MeshNode *> & nodes,
9153                            vector<int> &                   nbNodeInFaces )
9154   {
9155     nodes.clear();
9156     nbNodeInFaces.clear();
9157     SMDS_VolumeTool vTool ( elem );
9158     for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
9159     {
9160       const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
9161       nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
9162       nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
9163     }
9164   }
9165 }
9166
9167 //=======================================================================
9168 /*!
9169  * \brief Convert elements contained in a sub-mesh to quadratic
9170  * \return int - nb of checked elements
9171  */
9172 //=======================================================================
9173
9174 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9175                                              SMESH_MesherHelper& theHelper,
9176                                              const bool          theForce3d)
9177 {
9178   int nbElem = 0;
9179   if( !theSm ) return nbElem;
9180
9181   vector<int> nbNodeInFaces;
9182   vector<const SMDS_MeshNode *> nodes;
9183   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9184   while(ElemItr->more())
9185   {
9186     nbElem++;
9187     const SMDS_MeshElement* elem = ElemItr->next();
9188     if( !elem ) continue;
9189
9190     // analyse a necessity of conversion
9191     const SMDSAbs_ElementType aType = elem->GetType();
9192     if ( aType < SMDSAbs_Edge || aType > SMDSAbs_Volume )
9193       continue;
9194     const SMDSAbs_EntityType aGeomType = elem->GetEntityType();
9195     bool hasCentralNodes = false;
9196     if ( elem->IsQuadratic() )
9197     {
9198       bool alreadyOK;
9199       switch ( aGeomType ) {
9200       case SMDSEntity_Quad_Triangle:
9201       case SMDSEntity_Quad_Quadrangle:
9202       case SMDSEntity_Quad_Hexa:
9203         alreadyOK = !theHelper.GetIsBiQuadratic(); break;
9204
9205       case SMDSEntity_BiQuad_Triangle:
9206       case SMDSEntity_BiQuad_Quadrangle:
9207       case SMDSEntity_TriQuad_Hexa:
9208         alreadyOK = theHelper.GetIsBiQuadratic();
9209         hasCentralNodes = true;
9210         break;
9211       default:
9212         alreadyOK = true;
9213       }
9214       // take into account already present modium nodes
9215       switch ( aType ) {
9216       case SMDSAbs_Volume:
9217         theHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( elem )); break;
9218       case SMDSAbs_Face:
9219         theHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem )); break;
9220       case SMDSAbs_Edge:
9221         theHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( elem )); break;
9222       default:;
9223       }
9224       if ( alreadyOK )
9225         continue;
9226     }
9227     // get elem data needed to re-create it
9228     //
9229     const int id      = elem->GetID();
9230     const int nbNodes = elem->NbCornerNodes();
9231     nodes.assign(elem->begin_nodes(), elem->end_nodes());
9232     if ( aGeomType == SMDSEntity_Polyhedra )
9233       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9234     else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
9235       volumeToPolyhedron( elem, nodes, nbNodeInFaces );
9236
9237     // remove a linear element
9238     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9239
9240     // remove central nodes of biquadratic elements (biquad->quad convertion)
9241     if ( hasCentralNodes )
9242       for ( size_t i = nbNodes * 2; i < nodes.size(); ++i )
9243         if ( nodes[i]->NbInverseElements() == 0 )
9244           GetMeshDS()->RemoveFreeNode( nodes[i], theSm, /*fromGroups=*/true );
9245
9246     const SMDS_MeshElement* NewElem = 0;
9247
9248     switch( aType )
9249     {
9250     case SMDSAbs_Edge :
9251       {
9252         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9253         break;
9254       }
9255     case SMDSAbs_Face :
9256       {
9257         switch(nbNodes)
9258         {
9259         case 3:
9260           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9261           break;
9262         case 4:
9263           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9264           break;
9265         default:
9266           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9267         }
9268         break;
9269       }
9270     case SMDSAbs_Volume :
9271       {
9272         switch( aGeomType )
9273         {
9274         case SMDSEntity_Tetra:
9275           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9276           break;
9277         case SMDSEntity_Pyramid:
9278           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9279           break;
9280         case SMDSEntity_Penta:
9281           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9282           break;
9283         case SMDSEntity_Hexa:
9284         case SMDSEntity_Quad_Hexa:
9285         case SMDSEntity_TriQuad_Hexa:
9286           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9287                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9288           break;
9289         case SMDSEntity_Hexagonal_Prism:
9290         default:
9291           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9292         }
9293         break;
9294       }
9295     default :
9296       continue;
9297     }
9298     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9299     if( NewElem && NewElem->getshapeId() < 1 )
9300       theSm->AddElement( NewElem );
9301   }
9302   return nbElem;
9303 }
9304 //=======================================================================
9305 //function : ConvertToQuadratic
9306 //purpose  :
9307 //=======================================================================
9308
9309 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad)
9310 {
9311   SMESHDS_Mesh* meshDS = GetMeshDS();
9312
9313   SMESH_MesherHelper aHelper(*myMesh);
9314
9315   aHelper.SetIsQuadratic( true );
9316   aHelper.SetIsBiQuadratic( theToBiQuad );
9317   aHelper.SetElementsOnShape(true);
9318   aHelper.ToFixNodeParameters( true );
9319
9320   // convert elements assigned to sub-meshes
9321   int nbCheckedElems = 0;
9322   if ( myMesh->HasShapeToMesh() )
9323   {
9324     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9325     {
9326       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9327       while ( smIt->more() ) {
9328         SMESH_subMesh* sm = smIt->next();
9329         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9330           aHelper.SetSubShape( sm->GetSubShape() );
9331           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9332         }
9333       }
9334     }
9335   }
9336
9337   // convert elements NOT assigned to sub-meshes
9338   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9339   if ( nbCheckedElems < totalNbElems ) // not all elements are in sub-meshes
9340   {
9341     aHelper.SetElementsOnShape(false);
9342     SMESHDS_SubMesh *smDS = 0;
9343
9344     // convert edges
9345     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9346     while( aEdgeItr->more() )
9347     {
9348       const SMDS_MeshEdge* edge = aEdgeItr->next();
9349       if ( !edge->IsQuadratic() )
9350       {
9351         int                  id = edge->GetID();
9352         const SMDS_MeshNode* n1 = edge->GetNode(0);
9353         const SMDS_MeshNode* n2 = edge->GetNode(1);
9354
9355         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9356
9357         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9358         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9359       }
9360       else
9361       {
9362         aHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( edge ));
9363       }
9364     }
9365
9366     // convert faces
9367     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9368     while( aFaceItr->more() )
9369     {
9370       const SMDS_MeshFace* face = aFaceItr->next();
9371       if ( !face ) continue;
9372       
9373       const SMDSAbs_EntityType type = face->GetEntityType();
9374       bool alreadyOK;
9375       switch( type )
9376       {
9377       case SMDSEntity_Quad_Triangle:
9378       case SMDSEntity_Quad_Quadrangle:
9379         alreadyOK = !theToBiQuad;
9380         aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
9381         break;
9382       case SMDSEntity_BiQuad_Triangle:
9383       case SMDSEntity_BiQuad_Quadrangle:
9384         alreadyOK = theToBiQuad;
9385         aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
9386         break;
9387       default: alreadyOK = false;
9388       }
9389       if ( alreadyOK )
9390         continue;
9391
9392       const int id = face->GetID();
9393       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9394
9395       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9396
9397       SMDS_MeshFace * NewFace = 0;
9398       switch( type )
9399       {
9400       case SMDSEntity_Triangle:
9401       case SMDSEntity_Quad_Triangle:
9402       case SMDSEntity_BiQuad_Triangle:
9403         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9404         if ( nodes.size() == 7 && nodes[6]->NbInverseElements() == 0 ) // rm a central node
9405           GetMeshDS()->RemoveFreeNode( nodes[6], /*sm=*/0, /*fromGroups=*/true );
9406         break;
9407
9408       case SMDSEntity_Quadrangle:
9409       case SMDSEntity_Quad_Quadrangle:
9410       case SMDSEntity_BiQuad_Quadrangle:
9411         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9412         if ( nodes.size() == 9 && nodes[8]->NbInverseElements() == 0 ) // rm a central node
9413           GetMeshDS()->RemoveFreeNode( nodes[8], /*sm=*/0, /*fromGroups=*/true );
9414         break;
9415
9416       default:;
9417         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9418       }
9419       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9420     }
9421
9422     // convert volumes
9423     vector<int> nbNodeInFaces;
9424     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9425     while(aVolumeItr->more())
9426     {
9427       const SMDS_MeshVolume* volume = aVolumeItr->next();
9428       if ( !volume ) continue;
9429
9430       const SMDSAbs_EntityType type = volume->GetEntityType();
9431       if ( volume->IsQuadratic() )
9432       {
9433         bool alreadyOK;
9434         switch ( type )
9435         {
9436         case SMDSEntity_Quad_Hexa:    alreadyOK = !theToBiQuad; break;
9437         case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; break;
9438         default:                      alreadyOK = true;
9439         }
9440         if ( alreadyOK )
9441         {
9442           aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume ));
9443           continue;
9444         }
9445       }
9446       const int id = volume->GetID();
9447       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9448       if ( type == SMDSEntity_Polyhedra )
9449         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9450       else if ( type == SMDSEntity_Hexagonal_Prism )
9451         volumeToPolyhedron( volume, nodes, nbNodeInFaces );
9452
9453       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9454
9455       SMDS_MeshVolume * NewVolume = 0;
9456       switch ( type )
9457       {
9458       case SMDSEntity_Tetra:
9459         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
9460         break;
9461       case SMDSEntity_Hexa:
9462       case SMDSEntity_Quad_Hexa:
9463       case SMDSEntity_TriQuad_Hexa:
9464         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9465                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9466         for ( size_t i = 20; i < nodes.size(); ++i ) // rm central nodes
9467           if ( nodes[i]->NbInverseElements() == 0 )
9468             GetMeshDS()->RemoveFreeNode( nodes[i], /*sm=*/0, /*fromGroups=*/true );
9469         break;
9470       case SMDSEntity_Pyramid:
9471         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9472                                       nodes[3], nodes[4], id, theForce3d);
9473         break;
9474       case SMDSEntity_Penta:
9475         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9476                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9477         break;
9478       case SMDSEntity_Hexagonal_Prism:
9479       default:
9480         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9481       }
9482       ReplaceElemInGroups(volume, NewVolume, meshDS);
9483     }
9484   }
9485
9486   if ( !theForce3d )
9487   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9488     // aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9489     // aHelper.FixQuadraticElements(myError);
9490     SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
9491   }
9492 }
9493
9494 //================================================================================
9495 /*!
9496  * \brief Makes given elements quadratic
9497  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9498  *  \param theElements - elements to make quadratic
9499  */
9500 //================================================================================
9501
9502 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9503                                           TIDSortedElemSet& theElements,
9504                                           const bool        theToBiQuad)
9505 {
9506   if ( theElements.empty() ) return;
9507
9508   // we believe that all theElements are of the same type
9509   const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9510
9511   // get all nodes shared by theElements
9512   TIDSortedNodeSet allNodes;
9513   TIDSortedElemSet::iterator eIt = theElements.begin();
9514   for ( ; eIt != theElements.end(); ++eIt )
9515     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9516
9517   // complete theElements with elements of lower dim whose all nodes are in allNodes
9518
9519   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9520   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9521   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9522   for ( ; nIt != allNodes.end(); ++nIt )
9523   {
9524     const SMDS_MeshNode* n = *nIt;
9525     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9526     while ( invIt->more() )
9527     {
9528       const SMDS_MeshElement*      e = invIt->next();
9529       const SMDSAbs_ElementType type = e->GetType();
9530       if ( e->IsQuadratic() )
9531       {
9532         quadAdjacentElems[ type ].insert( e );
9533
9534         bool alreadyOK;
9535         switch ( e->GetEntityType() ) {
9536         case SMDSEntity_Quad_Triangle:
9537         case SMDSEntity_Quad_Quadrangle:
9538         case SMDSEntity_Quad_Hexa:         alreadyOK = !theToBiQuad; break;
9539         case SMDSEntity_BiQuad_Triangle:
9540         case SMDSEntity_BiQuad_Quadrangle:
9541         case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; break;
9542         default:                           alreadyOK = true;
9543         }
9544         if ( alreadyOK )
9545           continue;
9546       }
9547       if ( type >= elemType )
9548         continue; // same type or more complex linear element
9549
9550       if ( !checkedAdjacentElems[ type ].insert( e ).second )
9551         continue; // e is already checked
9552
9553       // check nodes
9554       bool allIn = true;
9555       SMDS_NodeIteratorPtr nodeIt = e->nodeIterator();
9556       while ( nodeIt->more() && allIn )
9557         allIn = allNodes.count( nodeIt->next() );
9558       if ( allIn )
9559         theElements.insert(e );
9560     }
9561   }
9562
9563   SMESH_MesherHelper helper(*myMesh);
9564   helper.SetIsQuadratic( true );
9565   helper.SetIsBiQuadratic( theToBiQuad );
9566
9567   // add links of quadratic adjacent elements to the helper
9568
9569   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9570     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9571           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9572     {
9573       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9574     }
9575   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9576     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9577           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9578     {
9579       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9580     }
9581   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9582     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9583           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9584     {
9585       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9586     }
9587
9588   // make quadratic (or bi-tri-quadratic) elements instead of linear ones
9589
9590   SMESHDS_Mesh*  meshDS = GetMeshDS();
9591   SMESHDS_SubMesh* smDS = 0;
9592   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9593   {
9594     const SMDS_MeshElement* elem = *eIt;
9595
9596     bool alreadyOK;
9597     int nbCentralNodes = 0;
9598     switch ( elem->GetEntityType() ) {
9599       // linear convertible
9600     case SMDSEntity_Edge:
9601     case SMDSEntity_Triangle:
9602     case SMDSEntity_Quadrangle:
9603     case SMDSEntity_Tetra:
9604     case SMDSEntity_Pyramid:
9605     case SMDSEntity_Hexa:
9606     case SMDSEntity_Penta:             alreadyOK = false;       nbCentralNodes = 0; break;
9607       // quadratic that can become bi-quadratic
9608     case SMDSEntity_Quad_Triangle:
9609     case SMDSEntity_Quad_Quadrangle:
9610     case SMDSEntity_Quad_Hexa:         alreadyOK =!theToBiQuad; nbCentralNodes = 0; break;
9611       // bi-quadratic
9612     case SMDSEntity_BiQuad_Triangle:
9613     case SMDSEntity_BiQuad_Quadrangle: alreadyOK = theToBiQuad; nbCentralNodes = 1; break;
9614     case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; nbCentralNodes = 7; break;
9615       // the rest
9616     default:                           alreadyOK = true;
9617     }
9618     if ( alreadyOK ) continue;
9619
9620     const SMDSAbs_ElementType type = elem->GetType();
9621     const int                   id = elem->GetID();
9622     const int              nbNodes = elem->NbCornerNodes();
9623     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9624
9625     helper.SetSubShape( elem->getshapeId() );
9626
9627     if ( !smDS || !smDS->Contains( elem ))
9628       smDS = meshDS->MeshElements( elem->getshapeId() );
9629     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9630
9631     SMDS_MeshElement * newElem = 0;
9632     switch( nbNodes )
9633     {
9634     case 4: // cases for most frequently used element types go first (for optimization)
9635       if ( type == SMDSAbs_Volume )
9636         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9637       else
9638         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9639       break;
9640     case 8:
9641       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9642                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9643       break;
9644     case 3:
9645       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9646       break;
9647     case 2:
9648       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9649       break;
9650     case 5:
9651       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9652                                  nodes[4], id, theForce3d);
9653       break;
9654     case 6:
9655       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9656                                  nodes[4], nodes[5], id, theForce3d);
9657       break;
9658     default:;
9659     }
9660     ReplaceElemInGroups( elem, newElem, meshDS);
9661     if( newElem && smDS )
9662       smDS->AddElement( newElem );
9663
9664      // remove central nodes
9665     for ( size_t i = nodes.size() - nbCentralNodes; i < nodes.size(); ++i )
9666       if ( nodes[i]->NbInverseElements() == 0 )
9667         meshDS->RemoveFreeNode( nodes[i], smDS, /*fromGroups=*/true );
9668
9669   } // loop on theElements
9670
9671   if ( !theForce3d )
9672   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9673     // helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9674     // helper.FixQuadraticElements( myError );
9675     SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
9676   }
9677 }
9678
9679 //=======================================================================
9680 /*!
9681  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9682  * \return int - nb of checked elements
9683  */
9684 //=======================================================================
9685
9686 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9687                                      SMDS_ElemIteratorPtr theItr,
9688                                      const int            theShapeID)
9689 {
9690   int nbElem = 0;
9691   SMESHDS_Mesh* meshDS = GetMeshDS();
9692   ElemFeatures elemType;
9693   vector<const SMDS_MeshNode *> nodes;
9694
9695   while( theItr->more() )
9696   {
9697     const SMDS_MeshElement* elem = theItr->next();
9698     nbElem++;
9699     if( elem && elem->IsQuadratic())
9700     {
9701       // get elem data
9702       int nbCornerNodes = elem->NbCornerNodes();
9703       nodes.assign( elem->begin_nodes(), elem->end_nodes() );
9704
9705       elemType.Init( elem, /*basicOnly=*/false ).SetID( elem->GetID() ).SetQuad( false );
9706
9707       //remove a quadratic element
9708       if ( !theSm || !theSm->Contains( elem ))
9709         theSm = meshDS->MeshElements( elem->getshapeId() );
9710       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9711
9712       // remove medium nodes
9713       for ( size_t i = nbCornerNodes; i < nodes.size(); ++i )
9714         if ( nodes[i]->NbInverseElements() == 0 )
9715           meshDS->RemoveFreeNode( nodes[i], theSm );
9716
9717       // add a linear element
9718       nodes.resize( nbCornerNodes );
9719       SMDS_MeshElement * newElem = AddElement( nodes, elemType );
9720       ReplaceElemInGroups(elem, newElem, meshDS);
9721       if( theSm && newElem )
9722         theSm->AddElement( newElem );
9723     }
9724   }
9725   return nbElem;
9726 }
9727
9728 //=======================================================================
9729 //function : ConvertFromQuadratic
9730 //purpose  :
9731 //=======================================================================
9732
9733 bool SMESH_MeshEditor::ConvertFromQuadratic()
9734 {
9735   int nbCheckedElems = 0;
9736   if ( myMesh->HasShapeToMesh() )
9737   {
9738     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9739     {
9740       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9741       while ( smIt->more() ) {
9742         SMESH_subMesh* sm = smIt->next();
9743         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9744           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9745       }
9746     }
9747   }
9748
9749   int totalNbElems =
9750     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9751   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9752   {
9753     SMESHDS_SubMesh *aSM = 0;
9754     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9755   }
9756
9757   return true;
9758 }
9759
9760 namespace
9761 {
9762   //================================================================================
9763   /*!
9764    * \brief Return true if all medium nodes of the element are in the node set
9765    */
9766   //================================================================================
9767
9768   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9769   {
9770     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9771       if ( !nodeSet.count( elem->GetNode(i) ))
9772         return false;
9773     return true;
9774   }
9775 }
9776
9777 //================================================================================
9778 /*!
9779  * \brief Makes given elements linear
9780  */
9781 //================================================================================
9782
9783 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9784 {
9785   if ( theElements.empty() ) return;
9786
9787   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9788   set<int> mediumNodeIDs;
9789   TIDSortedElemSet::iterator eIt = theElements.begin();
9790   for ( ; eIt != theElements.end(); ++eIt )
9791   {
9792     const SMDS_MeshElement* e = *eIt;
9793     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9794       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9795   }
9796
9797   // replace given elements by linear ones
9798   SMDS_ElemIteratorPtr elemIt = elemSetIterator( theElements );
9799   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9800
9801   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9802   // except those elements sharing medium nodes of quadratic element whose medium nodes
9803   // are not all in mediumNodeIDs
9804
9805   // get remaining medium nodes
9806   TIDSortedNodeSet mediumNodes;
9807   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9808   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9809     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9810       mediumNodes.insert( mediumNodes.end(), n );
9811
9812   // find more quadratic elements to convert
9813   TIDSortedElemSet moreElemsToConvert;
9814   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9815   for ( ; nIt != mediumNodes.end(); ++nIt )
9816   {
9817     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9818     while ( invIt->more() )
9819     {
9820       const SMDS_MeshElement* e = invIt->next();
9821       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9822       {
9823         // find a more complex element including e and
9824         // whose medium nodes are not in mediumNodes
9825         bool complexFound = false;
9826         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9827         {
9828           SMDS_ElemIteratorPtr invIt2 =
9829             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9830           while ( invIt2->more() )
9831           {
9832             const SMDS_MeshElement* eComplex = invIt2->next();
9833             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9834             {
9835               int nbCommonNodes = SMESH_MeshAlgos::GetCommonNodes( e, eComplex ).size();
9836               if ( nbCommonNodes == e->NbNodes())
9837               {
9838                 complexFound = true;
9839                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9840                 break;
9841               }
9842             }
9843           }
9844         }
9845         if ( !complexFound )
9846           moreElemsToConvert.insert( e );
9847       }
9848     }
9849   }
9850   elemIt = elemSetIterator( moreElemsToConvert );
9851   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9852 }
9853
9854 //=======================================================================
9855 //function : SewSideElements
9856 //purpose  :
9857 //=======================================================================
9858
9859 SMESH_MeshEditor::Sew_Error
9860 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9861                                    TIDSortedElemSet&    theSide2,
9862                                    const SMDS_MeshNode* theFirstNode1,
9863                                    const SMDS_MeshNode* theFirstNode2,
9864                                    const SMDS_MeshNode* theSecondNode1,
9865                                    const SMDS_MeshNode* theSecondNode2)
9866 {
9867   myLastCreatedElems.Clear();
9868   myLastCreatedNodes.Clear();
9869
9870   MESSAGE ("::::SewSideElements()");
9871   if ( theSide1.size() != theSide2.size() )
9872     return SEW_DIFF_NB_OF_ELEMENTS;
9873
9874   Sew_Error aResult = SEW_OK;
9875   // Algo:
9876   // 1. Build set of faces representing each side
9877   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9878   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9879
9880   // =======================================================================
9881   // 1. Build set of faces representing each side:
9882   // =======================================================================
9883   // a. build set of nodes belonging to faces
9884   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9885   // c. create temporary faces representing side of volumes if correspondent
9886   //    face does not exist
9887
9888   SMESHDS_Mesh* aMesh = GetMeshDS();
9889   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9890   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9891   TIDSortedElemSet             faceSet1, faceSet2;
9892   set<const SMDS_MeshElement*> volSet1,  volSet2;
9893   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9894   TIDSortedElemSet             * faceSetPtr[] = { &faceSet1, &faceSet2 };
9895   set<const SMDS_MeshElement*> *  volSetPtr[] = { &volSet1,  &volSet2  };
9896   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9897   TIDSortedElemSet             * elemSetPtr[] = { &theSide1, &theSide2 };
9898   int iSide, iFace, iNode;
9899
9900   list<const SMDS_MeshElement* > tempFaceList;
9901   for ( iSide = 0; iSide < 2; iSide++ ) {
9902     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9903     TIDSortedElemSet             * elemSet = elemSetPtr[ iSide ];
9904     TIDSortedElemSet             * faceSet = faceSetPtr[ iSide ];
9905     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9906     set<const SMDS_MeshElement*>::iterator vIt;
9907     TIDSortedElemSet::iterator eIt;
9908     set<const SMDS_MeshNode*>::iterator    nIt;
9909
9910     // check that given nodes belong to given elements
9911     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9912     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9913     int firstIndex = -1, secondIndex = -1;
9914     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9915       const SMDS_MeshElement* elem = *eIt;
9916       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9917       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9918       if ( firstIndex > -1 && secondIndex > -1 ) break;
9919     }
9920     if ( firstIndex < 0 || secondIndex < 0 ) {
9921       // we can simply return until temporary faces created
9922       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9923     }
9924
9925     // -----------------------------------------------------------
9926     // 1a. Collect nodes of existing faces
9927     //     and build set of face nodes in order to detect missing
9928     //     faces corresponding to sides of volumes
9929     // -----------------------------------------------------------
9930
9931     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9932
9933     // loop on the given element of a side
9934     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9935       //const SMDS_MeshElement* elem = *eIt;
9936       const SMDS_MeshElement* elem = *eIt;
9937       if ( elem->GetType() == SMDSAbs_Face ) {
9938         faceSet->insert( elem );
9939         set <const SMDS_MeshNode*> faceNodeSet;
9940         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9941         while ( nodeIt->more() ) {
9942           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9943           nodeSet->insert( n );
9944           faceNodeSet.insert( n );
9945         }
9946         setOfFaceNodeSet.insert( faceNodeSet );
9947       }
9948       else if ( elem->GetType() == SMDSAbs_Volume )
9949         volSet->insert( elem );
9950     }
9951     // ------------------------------------------------------------------------------
9952     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9953     // ------------------------------------------------------------------------------
9954
9955     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9956       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9957       while ( fIt->more() ) { // loop on faces sharing a node
9958         const SMDS_MeshElement* f = fIt->next();
9959         if ( faceSet->find( f ) == faceSet->end() ) {
9960           // check if all nodes are in nodeSet and
9961           // complete setOfFaceNodeSet if they are
9962           set <const SMDS_MeshNode*> faceNodeSet;
9963           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9964           bool allInSet = true;
9965           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9966             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9967             if ( nodeSet->find( n ) == nodeSet->end() )
9968               allInSet = false;
9969             else
9970               faceNodeSet.insert( n );
9971           }
9972           if ( allInSet ) {
9973             faceSet->insert( f );
9974             setOfFaceNodeSet.insert( faceNodeSet );
9975           }
9976         }
9977       }
9978     }
9979
9980     // -------------------------------------------------------------------------
9981     // 1c. Create temporary faces representing sides of volumes if correspondent
9982     //     face does not exist
9983     // -------------------------------------------------------------------------
9984
9985     if ( !volSet->empty() ) {
9986       //int nodeSetSize = nodeSet->size();
9987
9988       // loop on given volumes
9989       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9990         SMDS_VolumeTool vol (*vIt);
9991         // loop on volume faces: find free faces
9992         // --------------------------------------
9993         list<const SMDS_MeshElement* > freeFaceList;
9994         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9995           if ( !vol.IsFreeFace( iFace ))
9996             continue;
9997           // check if there is already a face with same nodes in a face set
9998           const SMDS_MeshElement* aFreeFace = 0;
9999           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
10000           int nbNodes = vol.NbFaceNodes( iFace );
10001           set <const SMDS_MeshNode*> faceNodeSet;
10002           vol.GetFaceNodes( iFace, faceNodeSet );
10003           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
10004           if ( isNewFace ) {
10005             // no such a face is given but it still can exist, check it
10006             vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
10007             aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
10008           }
10009           if ( !aFreeFace ) {
10010             // create a temporary face
10011             if ( nbNodes == 3 ) {
10012               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
10013               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
10014             }
10015             else if ( nbNodes == 4 ) {
10016               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10017               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10018             }
10019             else {
10020               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
10021               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
10022               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
10023             }
10024             if ( aFreeFace )
10025               tempFaceList.push_back( aFreeFace );
10026           }
10027
10028           if ( aFreeFace )
10029             freeFaceList.push_back( aFreeFace );
10030
10031         } // loop on faces of a volume
10032
10033         // choose one of several free faces of a volume
10034         // --------------------------------------------
10035         if ( freeFaceList.size() > 1 ) {
10036           // choose a face having max nb of nodes shared by other elems of a side
10037           int maxNbNodes = -1;
10038           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
10039           while ( fIt != freeFaceList.end() ) { // loop on free faces
10040             int nbSharedNodes = 0;
10041             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
10042             while ( nodeIt->more() ) { // loop on free face nodes
10043               const SMDS_MeshNode* n =
10044                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10045               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
10046               while ( invElemIt->more() ) {
10047                 const SMDS_MeshElement* e = invElemIt->next();
10048                 nbSharedNodes += faceSet->count( e );
10049                 nbSharedNodes += elemSet->count( e );
10050               }
10051             }
10052             if ( nbSharedNodes > maxNbNodes ) {
10053               maxNbNodes = nbSharedNodes;
10054               freeFaceList.erase( freeFaceList.begin(), fIt++ );
10055             }
10056             else if ( nbSharedNodes == maxNbNodes ) {
10057               fIt++;
10058             }
10059             else {
10060               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
10061             }
10062           }
10063           if ( freeFaceList.size() > 1 )
10064           {
10065             // could not choose one face, use another way
10066             // choose a face most close to the bary center of the opposite side
10067             gp_XYZ aBC( 0., 0., 0. );
10068             set <const SMDS_MeshNode*> addedNodes;
10069             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
10070             eIt = elemSet2->begin();
10071             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
10072               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
10073               while ( nodeIt->more() ) { // loop on free face nodes
10074                 const SMDS_MeshNode* n =
10075                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10076                 if ( addedNodes.insert( n ).second )
10077                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
10078               }
10079             }
10080             aBC /= addedNodes.size();
10081             double minDist = DBL_MAX;
10082             fIt = freeFaceList.begin();
10083             while ( fIt != freeFaceList.end() ) { // loop on free faces
10084               double dist = 0;
10085               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
10086               while ( nodeIt->more() ) { // loop on free face nodes
10087                 const SMDS_MeshNode* n =
10088                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10089                 gp_XYZ p( n->X(),n->Y(),n->Z() );
10090                 dist += ( aBC - p ).SquareModulus();
10091               }
10092               if ( dist < minDist ) {
10093                 minDist = dist;
10094                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
10095               }
10096               else
10097                 fIt = freeFaceList.erase( fIt++ );
10098             }
10099           }
10100         } // choose one of several free faces of a volume
10101
10102         if ( freeFaceList.size() == 1 ) {
10103           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
10104           faceSet->insert( aFreeFace );
10105           // complete a node set with nodes of a found free face
10106           //           for ( iNode = 0; iNode < ; iNode++ )
10107           //             nodeSet->insert( fNodes[ iNode ] );
10108         }
10109
10110       } // loop on volumes of a side
10111
10112       //       // complete a set of faces if new nodes in a nodeSet appeared
10113       //       // ----------------------------------------------------------
10114       //       if ( nodeSetSize != nodeSet->size() ) {
10115       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10116       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10117       //           while ( fIt->more() ) { // loop on faces sharing a node
10118       //             const SMDS_MeshElement* f = fIt->next();
10119       //             if ( faceSet->find( f ) == faceSet->end() ) {
10120       //               // check if all nodes are in nodeSet and
10121       //               // complete setOfFaceNodeSet if they are
10122       //               set <const SMDS_MeshNode*> faceNodeSet;
10123       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10124       //               bool allInSet = true;
10125       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10126       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10127       //                 if ( nodeSet->find( n ) == nodeSet->end() )
10128       //                   allInSet = false;
10129       //                 else
10130       //                   faceNodeSet.insert( n );
10131       //               }
10132       //               if ( allInSet ) {
10133       //                 faceSet->insert( f );
10134       //                 setOfFaceNodeSet.insert( faceNodeSet );
10135       //               }
10136       //             }
10137       //           }
10138       //         }
10139       //       }
10140     } // Create temporary faces, if there are volumes given
10141   } // loop on sides
10142
10143   if ( faceSet1.size() != faceSet2.size() ) {
10144     // delete temporary faces: they are in reverseElements of actual nodes
10145 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10146 //    while ( tmpFaceIt->more() )
10147 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10148 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10149 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10150 //      aMesh->RemoveElement(*tmpFaceIt);
10151     MESSAGE("Diff nb of faces");
10152     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10153   }
10154
10155   // ============================================================
10156   // 2. Find nodes to merge:
10157   //              bind a node to remove to a node to put instead
10158   // ============================================================
10159
10160   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10161   if ( theFirstNode1 != theFirstNode2 )
10162     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10163   if ( theSecondNode1 != theSecondNode2 )
10164     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10165
10166   LinkID_Gen aLinkID_Gen( GetMeshDS() );
10167   set< long > linkIdSet; // links to process
10168   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10169
10170   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10171   list< NLink > linkList[2];
10172   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10173   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10174   // loop on links in linkList; find faces by links and append links
10175   // of the found faces to linkList
10176   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10177   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
10178   {
10179     NLink link[] = { *linkIt[0], *linkIt[1] };
10180     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10181     if ( !linkIdSet.count( linkID ) )
10182       continue;
10183
10184     // by links, find faces in the face sets,
10185     // and find indices of link nodes in the found faces;
10186     // in a face set, there is only one or no face sharing a link
10187     // ---------------------------------------------------------------
10188
10189     const SMDS_MeshElement* face[] = { 0, 0 };
10190     vector<const SMDS_MeshNode*> fnodes[2];
10191     int iLinkNode[2][2];
10192     TIDSortedElemSet avoidSet;
10193     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10194       const SMDS_MeshNode* n1 = link[iSide].first;
10195       const SMDS_MeshNode* n2 = link[iSide].second;
10196       //cout << "Side " << iSide << " ";
10197       //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
10198       // find a face by two link nodes
10199       face[ iSide ] = SMESH_MeshAlgos::FindFaceInSet( n1, n2,
10200                                                       *faceSetPtr[ iSide ], avoidSet,
10201                                                       &iLinkNode[iSide][0],
10202                                                       &iLinkNode[iSide][1] );
10203       if ( face[ iSide ])
10204       {
10205         //cout << " F " << face[ iSide]->GetID() <<endl;
10206         faceSetPtr[ iSide ]->erase( face[ iSide ]);
10207         // put face nodes to fnodes
10208         if ( face[ iSide ]->IsQuadratic() )
10209         {
10210           // use interlaced nodes iterator
10211           const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
10212           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10213           SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
10214           while ( nIter->more() )
10215             fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
10216         }
10217         else
10218         {
10219           fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
10220                                   face[ iSide ]->end_nodes() );
10221         }
10222         fnodes[ iSide ].push_back( fnodes[ iSide ].front());
10223       }
10224     }
10225
10226     // check similarity of elements of the sides
10227     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10228       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10229       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10230         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10231       }
10232       else {
10233         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10234       }
10235       break; // do not return because it's necessary to remove tmp faces
10236     }
10237
10238     // set nodes to merge
10239     // -------------------
10240
10241     if ( face[0] && face[1] )  {
10242       const int nbNodes = face[0]->NbNodes();
10243       if ( nbNodes != face[1]->NbNodes() ) {
10244         MESSAGE("Diff nb of face nodes");
10245         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10246         break; // do not return because it s necessary to remove tmp faces
10247       }
10248       bool reverse[] = { false, false }; // order of nodes in the link
10249       for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10250         // analyse link orientation in faces
10251         int i1 = iLinkNode[ iSide ][ 0 ];
10252         int i2 = iLinkNode[ iSide ][ 1 ];
10253         reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10254       }
10255       int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
10256       int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
10257       for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
10258       {
10259         nReplaceMap.insert  ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
10260                                           fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
10261       }
10262
10263       // add other links of the faces to linkList
10264       // -----------------------------------------
10265
10266       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10267         linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
10268         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10269         if ( !iter_isnew.second ) { // already in a set: no need to process
10270           linkIdSet.erase( iter_isnew.first );
10271         }
10272         else // new in set == encountered for the first time: add
10273         {
10274           const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
10275           const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
10276           linkList[0].push_back ( NLink( n1, n2 ));
10277           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10278         }
10279       }
10280     } // 2 faces found
10281
10282     if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
10283       break;
10284
10285   } // loop on link lists
10286
10287   if ( aResult == SEW_OK &&
10288        ( //linkIt[0] != linkList[0].end() ||
10289          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10290     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10291              " " << (faceSetPtr[1]->empty()));
10292     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10293   }
10294
10295   // ====================================================================
10296   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10297   // ====================================================================
10298
10299   // delete temporary faces
10300 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10301 //  while ( tmpFaceIt->more() )
10302 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10303   list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10304   for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10305     aMesh->RemoveElement(*tmpFaceIt);
10306
10307   if ( aResult != SEW_OK)
10308     return aResult;
10309
10310   list< int > nodeIDsToRemove;
10311   vector< const SMDS_MeshNode*> nodes;
10312   ElemFeatures elemType;
10313
10314   // loop on nodes replacement map
10315   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10316   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10317     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second )
10318     {
10319       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10320       nodeIDsToRemove.push_back( nToRemove->GetID() );
10321       // loop on elements sharing nToRemove
10322       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10323       while ( invElemIt->more() ) {
10324         const SMDS_MeshElement* e = invElemIt->next();
10325         // get a new suite of nodes: make replacement
10326         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10327         nodes.resize( nbNodes );
10328         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10329         while ( nIt->more() ) {
10330           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nIt->next() );
10331           nnIt = nReplaceMap.find( n );
10332           if ( nnIt != nReplaceMap.end() ) {
10333             nbReplaced++;
10334             n = (*nnIt).second;
10335           }
10336           nodes[ i++ ] = n;
10337         }
10338         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10339         //         elemIDsToRemove.push_back( e->GetID() );
10340         //       else
10341         if ( nbReplaced )
10342         {
10343           elemType.Init( e, /*basicOnly=*/false ).SetID( e->GetID() );
10344           aMesh->RemoveElement( e );
10345
10346           if ( SMDS_MeshElement* newElem = this->AddElement( nodes, elemType ))
10347           {
10348             AddToSameGroups( newElem, e, aMesh );
10349             if ( int aShapeId = e->getshapeId() )
10350               aMesh->SetMeshElementOnShape( newElem, aShapeId );
10351           }
10352         }
10353       }
10354     }
10355
10356   Remove( nodeIDsToRemove, true );
10357
10358   return aResult;
10359 }
10360
10361 //================================================================================
10362 /*!
10363  * \brief Find corresponding nodes in two sets of faces
10364  * \param theSide1 - first face set
10365  * \param theSide2 - second first face
10366  * \param theFirstNode1 - a boundary node of set 1
10367  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10368  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10369  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10370  * \param nReplaceMap - output map of corresponding nodes
10371  * \return bool  - is a success or not
10372  */
10373 //================================================================================
10374
10375 #ifdef _DEBUG_
10376 //#define DEBUG_MATCHING_NODES
10377 #endif
10378
10379 SMESH_MeshEditor::Sew_Error
10380 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10381                                     set<const SMDS_MeshElement*>& theSide2,
10382                                     const SMDS_MeshNode*          theFirstNode1,
10383                                     const SMDS_MeshNode*          theFirstNode2,
10384                                     const SMDS_MeshNode*          theSecondNode1,
10385                                     const SMDS_MeshNode*          theSecondNode2,
10386                                     TNodeNodeMap &                nReplaceMap)
10387 {
10388   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10389
10390   nReplaceMap.clear();
10391   if ( theFirstNode1 != theFirstNode2 )
10392     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10393   if ( theSecondNode1 != theSecondNode2 )
10394     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10395
10396   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10397   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10398
10399   list< NLink > linkList[2];
10400   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10401   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10402
10403   // loop on links in linkList; find faces by links and append links
10404   // of the found faces to linkList
10405   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10406   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10407     NLink link[] = { *linkIt[0], *linkIt[1] };
10408     if ( linkSet.find( link[0] ) == linkSet.end() )
10409       continue;
10410
10411     // by links, find faces in the face sets,
10412     // and find indices of link nodes in the found faces;
10413     // in a face set, there is only one or no face sharing a link
10414     // ---------------------------------------------------------------
10415
10416     const SMDS_MeshElement* face[] = { 0, 0 };
10417     list<const SMDS_MeshNode*> notLinkNodes[2];
10418     //bool reverse[] = { false, false }; // order of notLinkNodes
10419     int nbNodes[2];
10420     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10421     {
10422       const SMDS_MeshNode* n1 = link[iSide].first;
10423       const SMDS_MeshNode* n2 = link[iSide].second;
10424       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10425       set< const SMDS_MeshElement* > facesOfNode1;
10426       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10427       {
10428         // during a loop of the first node, we find all faces around n1,
10429         // during a loop of the second node, we find one face sharing both n1 and n2
10430         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10431         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10432         while ( fIt->more() ) { // loop on faces sharing a node
10433           const SMDS_MeshElement* f = fIt->next();
10434           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10435               ! facesOfNode1.insert( f ).second ) // f encounters twice
10436           {
10437             if ( face[ iSide ] ) {
10438               MESSAGE( "2 faces per link " );
10439               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10440             }
10441             face[ iSide ] = f;
10442             faceSet->erase( f );
10443
10444             // get not link nodes
10445             int nbN = f->NbNodes();
10446             if ( f->IsQuadratic() )
10447               nbN /= 2;
10448             nbNodes[ iSide ] = nbN;
10449             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10450             int i1 = f->GetNodeIndex( n1 );
10451             int i2 = f->GetNodeIndex( n2 );
10452             int iEnd = nbN, iBeg = -1, iDelta = 1;
10453             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10454             if ( reverse ) {
10455               std::swap( iEnd, iBeg ); iDelta = -1;
10456             }
10457             int i = i2;
10458             while ( true ) {
10459               i += iDelta;
10460               if ( i == iEnd ) i = iBeg + iDelta;
10461               if ( i == i1 ) break;
10462               nodes.push_back ( f->GetNode( i ) );
10463             }
10464           }
10465         }
10466       }
10467     }
10468     // check similarity of elements of the sides
10469     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10470       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10471       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10472         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10473       }
10474       else {
10475         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10476       }
10477     }
10478
10479     // set nodes to merge
10480     // -------------------
10481
10482     if ( face[0] && face[1] )  {
10483       if ( nbNodes[0] != nbNodes[1] ) {
10484         MESSAGE("Diff nb of face nodes");
10485         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10486       }
10487 #ifdef DEBUG_MATCHING_NODES
10488       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10489                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10490                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10491 #endif
10492       int nbN = nbNodes[0];
10493       {
10494         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10495         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10496         for ( int i = 0 ; i < nbN - 2; ++i ) {
10497 #ifdef DEBUG_MATCHING_NODES
10498           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10499 #endif
10500           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10501         }
10502       }
10503
10504       // add other links of the face 1 to linkList
10505       // -----------------------------------------
10506
10507       const SMDS_MeshElement* f0 = face[0];
10508       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10509       for ( int i = 0; i < nbN; i++ )
10510       {
10511         const SMDS_MeshNode* n2 = f0->GetNode( i );
10512         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10513           linkSet.insert( SMESH_TLink( n1, n2 ));
10514         if ( !iter_isnew.second ) { // already in a set: no need to process
10515           linkSet.erase( iter_isnew.first );
10516         }
10517         else // new in set == encountered for the first time: add
10518         {
10519 #ifdef DEBUG_MATCHING_NODES
10520           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10521                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10522 #endif
10523           linkList[0].push_back ( NLink( n1, n2 ));
10524           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10525         }
10526         n1 = n2;
10527       }
10528     } // 2 faces found
10529   } // loop on link lists
10530
10531   return SEW_OK;
10532 }
10533
10534 //================================================================================
10535 /*!
10536  * \brief Create elements equal (on same nodes) to given ones
10537  *  \param [in] theElements - a set of elems to duplicate. If it is empty, all
10538  *              elements of the uppest dimension are duplicated.
10539  */
10540 //================================================================================
10541
10542 void SMESH_MeshEditor::DoubleElements( const TIDSortedElemSet& theElements )
10543 {
10544   ClearLastCreated();
10545   SMESHDS_Mesh* mesh = GetMeshDS();
10546
10547   // get an element type and an iterator over elements
10548
10549   SMDSAbs_ElementType type;
10550   SMDS_ElemIteratorPtr elemIt;
10551   vector< const SMDS_MeshElement* > allElems;
10552   if ( theElements.empty() )
10553   {
10554     if ( mesh->NbNodes() == 0 )
10555       return;
10556     // get most complex type
10557     SMDSAbs_ElementType types[SMDSAbs_NbElementTypes] = {
10558       SMDSAbs_Volume, SMDSAbs_Face, SMDSAbs_Edge,
10559       SMDSAbs_0DElement, SMDSAbs_Ball, SMDSAbs_Node
10560     };
10561     for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
10562       if ( mesh->GetMeshInfo().NbElements( types[i] ))
10563       {
10564         type = types[i];
10565         break;
10566       }
10567     // put all elements in the vector <allElems>
10568     allElems.reserve( mesh->GetMeshInfo().NbElements( type ));
10569     elemIt = mesh->elementsIterator( type );
10570     while ( elemIt->more() )
10571       allElems.push_back( elemIt->next());
10572     elemIt = elemSetIterator( allElems );
10573   }
10574   else
10575   {
10576     type = (*theElements.begin())->GetType();
10577     elemIt = elemSetIterator( theElements );
10578   }
10579
10580   // duplicate elements
10581
10582   ElemFeatures elemType;
10583
10584   vector< const SMDS_MeshNode* > nodes;
10585   while ( elemIt->more() )
10586   {
10587     const SMDS_MeshElement* elem = elemIt->next();
10588     if ( elem->GetType() != type )
10589       continue;
10590
10591     elemType.Init( elem, /*basicOnly=*/false );
10592     nodes.assign( elem->begin_nodes(), elem->end_nodes() );
10593
10594     AddElement( nodes, elemType );
10595   }
10596 }
10597
10598 //================================================================================
10599 /*!
10600   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10601   \param theElems - the list of elements (edges or faces) to be replicated
10602   The nodes for duplication could be found from these elements
10603   \param theNodesNot - list of nodes to NOT replicate
10604   \param theAffectedElems - the list of elements (cells and edges) to which the
10605   replicated nodes should be associated to.
10606   \return TRUE if operation has been completed successfully, FALSE otherwise
10607 */
10608 //================================================================================
10609
10610 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10611                                     const TIDSortedElemSet& theNodesNot,
10612                                     const TIDSortedElemSet& theAffectedElems )
10613 {
10614   myLastCreatedElems.Clear();
10615   myLastCreatedNodes.Clear();
10616
10617   if ( theElems.size() == 0 )
10618     return false;
10619
10620   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10621   if ( !aMeshDS )
10622     return false;
10623
10624   bool res = false;
10625   TNodeNodeMap anOldNodeToNewNode;
10626   // duplicate elements and nodes
10627   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10628   // replce nodes by duplications
10629   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10630   return res;
10631 }
10632
10633 //================================================================================
10634 /*!
10635   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10636   \param theMeshDS - mesh instance
10637   \param theElems - the elements replicated or modified (nodes should be changed)
10638   \param theNodesNot - nodes to NOT replicate
10639   \param theNodeNodeMap - relation of old node to new created node
10640   \param theIsDoubleElem - flag os to replicate element or modify
10641   \return TRUE if operation has been completed successfully, FALSE otherwise
10642 */
10643 //================================================================================
10644
10645 bool SMESH_MeshEditor::doubleNodes(SMESHDS_Mesh*           theMeshDS,
10646                                    const TIDSortedElemSet& theElems,
10647                                    const TIDSortedElemSet& theNodesNot,
10648                                    TNodeNodeMap&           theNodeNodeMap,
10649                                    const bool              theIsDoubleElem )
10650 {
10651   MESSAGE("doubleNodes");
10652   // iterate through element and duplicate them (by nodes duplication)
10653   bool res = false;
10654   std::vector<const SMDS_MeshNode*> newNodes;
10655   ElemFeatures elemType;
10656
10657   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10658   for ( ;  elemItr != theElems.end(); ++elemItr )
10659   {
10660     const SMDS_MeshElement* anElem = *elemItr;
10661     if (!anElem)
10662       continue;
10663
10664     // duplicate nodes to duplicate element
10665     bool isDuplicate = false;
10666     newNodes.resize( anElem->NbNodes() );
10667     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10668     int ind = 0;
10669     while ( anIter->more() )
10670     {
10671       const SMDS_MeshNode* aCurrNode = static_cast<const SMDS_MeshNode*>( anIter->next() );
10672       const SMDS_MeshNode*  aNewNode = aCurrNode;
10673       TNodeNodeMap::iterator     n2n = theNodeNodeMap.find( aCurrNode );
10674       if ( n2n != theNodeNodeMap.end() )
10675       {
10676         aNewNode = n2n->second;
10677       }
10678       else if ( theIsDoubleElem && !theNodesNot.count( aCurrNode ))
10679       {
10680         // duplicate node
10681         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10682         copyPosition( aCurrNode, aNewNode );
10683         theNodeNodeMap[ aCurrNode ] = aNewNode;
10684         myLastCreatedNodes.Append( aNewNode );
10685       }
10686       isDuplicate |= (aCurrNode != aNewNode);
10687       newNodes[ ind++ ] = aNewNode;
10688     }
10689     if ( !isDuplicate )
10690       continue;
10691
10692     if ( theIsDoubleElem )
10693       AddElement( newNodes, elemType.Init( anElem, /*basicOnly=*/false ));
10694     else
10695       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], newNodes.size() );
10696
10697     res = true;
10698   }
10699   return res;
10700 }
10701
10702 //================================================================================
10703 /*!
10704   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10705   \param theNodes - identifiers of nodes to be doubled
10706   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10707   nodes. If list of element identifiers is empty then nodes are doubled but
10708   they not assigned to elements
10709   \return TRUE if operation has been completed successfully, FALSE otherwise
10710 */
10711 //================================================================================
10712
10713 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10714                                     const std::list< int >& theListOfModifiedElems )
10715 {
10716   MESSAGE("DoubleNodes");
10717   myLastCreatedElems.Clear();
10718   myLastCreatedNodes.Clear();
10719
10720   if ( theListOfNodes.size() == 0 )
10721     return false;
10722
10723   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10724   if ( !aMeshDS )
10725     return false;
10726
10727   // iterate through nodes and duplicate them
10728
10729   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10730
10731   std::list< int >::const_iterator aNodeIter;
10732   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10733   {
10734     int aCurr = *aNodeIter;
10735     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10736     if ( !aNode )
10737       continue;
10738
10739     // duplicate node
10740
10741     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10742     if ( aNewNode )
10743     {
10744       copyPosition( aNode, aNewNode );
10745       anOldNodeToNewNode[ aNode ] = aNewNode;
10746       myLastCreatedNodes.Append( aNewNode );
10747     }
10748   }
10749
10750   // Create map of new nodes for modified elements
10751
10752   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10753
10754   std::list< int >::const_iterator anElemIter;
10755   for ( anElemIter = theListOfModifiedElems.begin();
10756         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10757   {
10758     int aCurr = *anElemIter;
10759     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10760     if ( !anElem )
10761       continue;
10762
10763     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10764
10765     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10766     int ind = 0;
10767     while ( anIter->more() )
10768     {
10769       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10770       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10771       {
10772         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10773         aNodeArr[ ind++ ] = aNewNode;
10774       }
10775       else
10776         aNodeArr[ ind++ ] = aCurrNode;
10777     }
10778     anElemToNodes[ anElem ] = aNodeArr;
10779   }
10780
10781   // Change nodes of elements
10782
10783   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10784     anElemToNodesIter = anElemToNodes.begin();
10785   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10786   {
10787     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10788     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10789     if ( anElem )
10790       {
10791       MESSAGE("ChangeElementNodes");
10792       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10793       }
10794   }
10795
10796   return true;
10797 }
10798
10799 namespace {
10800
10801   //================================================================================
10802   /*!
10803   \brief Check if element located inside shape
10804   \return TRUE if IN or ON shape, FALSE otherwise
10805   */
10806   //================================================================================
10807
10808   template<class Classifier>
10809   bool isInside(const SMDS_MeshElement* theElem,
10810                 Classifier&             theClassifier,
10811                 const double            theTol)
10812   {
10813     gp_XYZ centerXYZ (0, 0, 0);
10814     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10815     while (aNodeItr->more())
10816       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10817
10818     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10819     theClassifier.Perform(aPnt, theTol);
10820     TopAbs_State aState = theClassifier.State();
10821     return (aState == TopAbs_IN || aState == TopAbs_ON );
10822   }
10823
10824   //================================================================================
10825   /*!
10826    * \brief Classifier of the 3D point on the TopoDS_Face
10827    *        with interaface suitable for isInside()
10828    */
10829   //================================================================================
10830
10831   struct _FaceClassifier
10832   {
10833     Extrema_ExtPS       _extremum;
10834     BRepAdaptor_Surface _surface;
10835     TopAbs_State        _state;
10836
10837     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10838     {
10839       _extremum.Initialize( _surface,
10840                             _surface.FirstUParameter(), _surface.LastUParameter(),
10841                             _surface.FirstVParameter(), _surface.LastVParameter(),
10842                             _surface.Tolerance(), _surface.Tolerance() );
10843     }
10844     void Perform(const gp_Pnt& aPnt, double theTol)
10845     {
10846       theTol *= theTol;
10847       _state = TopAbs_OUT;
10848       _extremum.Perform(aPnt);
10849       if ( _extremum.IsDone() )
10850         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10851           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10852     }
10853     TopAbs_State State() const
10854     {
10855       return _state;
10856     }
10857   };
10858 }
10859
10860 //================================================================================
10861 /*!
10862   \brief Identify the elements that will be affected by node duplication (actual duplication is not performed).
10863   This method is the first step of DoubleNodeElemGroupsInRegion.
10864   \param theElems - list of groups of elements (edges or faces) to be replicated
10865   \param theNodesNot - list of groups of nodes not to replicated
10866   \param theShape - shape to detect affected elements (element which geometric center
10867          located on or inside shape). If the shape is null, detection is done on faces orientations
10868          (select elements with a gravity center on the side given by faces normals).
10869          This mode (null shape) is faster, but works only when theElems are faces, with coherents orientations.
10870          The replicated nodes should be associated to affected elements.
10871   \return groups of affected elements
10872   \sa DoubleNodeElemGroupsInRegion()
10873  */
10874 //================================================================================
10875
10876 bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
10877                                                    const TIDSortedElemSet& theNodesNot,
10878                                                    const TopoDS_Shape&     theShape,
10879                                                    TIDSortedElemSet&       theAffectedElems)
10880 {
10881   if ( theShape.IsNull() )
10882   {
10883     std::set<const SMDS_MeshNode*> alreadyCheckedNodes;
10884     std::set<const SMDS_MeshElement*> alreadyCheckedElems;
10885     std::set<const SMDS_MeshElement*> edgesToCheck;
10886     alreadyCheckedNodes.clear();
10887     alreadyCheckedElems.clear();
10888     edgesToCheck.clear();
10889
10890     // --- iterates on elements to be replicated and get elements by back references from their nodes
10891
10892     TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10893     int ielem;
10894     for ( ielem=1;  elemItr != theElems.end(); ++elemItr )
10895     {
10896       SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10897       if (!anElem || (anElem->GetType() != SMDSAbs_Face))
10898         continue;
10899       gp_XYZ normal;
10900       SMESH_MeshAlgos::FaceNormal( anElem, normal, /*normalized=*/true );
10901       MESSAGE("element " << ielem++ <<  " normal " << normal.X() << " " << normal.Y() << " " << normal.Z());
10902       std::set<const SMDS_MeshNode*> nodesElem;
10903       nodesElem.clear();
10904       SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10905       while ( nodeItr->more() )
10906       {
10907         const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10908         nodesElem.insert(aNode);
10909       }
10910       std::set<const SMDS_MeshNode*>::iterator nodit = nodesElem.begin();
10911       for (; nodit != nodesElem.end(); nodit++)
10912       {
10913         MESSAGE("  noeud ");
10914         const SMDS_MeshNode* aNode = *nodit;
10915         if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10916           continue;
10917         if (alreadyCheckedNodes.find(aNode) != alreadyCheckedNodes.end())
10918           continue;
10919         alreadyCheckedNodes.insert(aNode);
10920         SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10921         while ( backElemItr->more() )
10922         {
10923           MESSAGE("    backelem ");
10924           const SMDS_MeshElement* curElem = backElemItr->next();
10925           if (alreadyCheckedElems.find(curElem) != alreadyCheckedElems.end())
10926             continue;
10927           if (theElems.find(curElem) != theElems.end())
10928             continue;
10929           alreadyCheckedElems.insert(curElem);
10930           double x=0, y=0, z=0;
10931           int nb = 0;
10932           SMDS_ElemIteratorPtr nodeItr2 = curElem->nodesIterator();
10933           while ( nodeItr2->more() )
10934           {
10935             const SMDS_MeshNode* anotherNode = cast2Node(nodeItr2->next());
10936             x += anotherNode->X();
10937             y += anotherNode->Y();
10938             z += anotherNode->Z();
10939             nb++;
10940           }
10941           gp_XYZ p;
10942           p.SetCoord( x/nb -aNode->X(),
10943                       y/nb -aNode->Y(),
10944                       z/nb -aNode->Z() );
10945           MESSAGE("      check " << p.X() << " " << p.Y() << " " << p.Z());
10946           if (normal*p > 0)
10947           {
10948             MESSAGE("    --- inserted")
10949             theAffectedElems.insert( curElem );
10950           }
10951           else if (curElem->GetType() == SMDSAbs_Edge)
10952             edgesToCheck.insert(curElem);
10953         }
10954       }
10955     }
10956     // --- add also edges lying on the set of faces (all nodes in alreadyCheckedNodes)
10957     std::set<const SMDS_MeshElement*>::iterator eit = edgesToCheck.begin();
10958     for( ; eit != edgesToCheck.end(); eit++)
10959     {
10960       bool onside = true;
10961       const SMDS_MeshElement* anEdge = *eit;
10962       SMDS_ElemIteratorPtr nodeItr = anEdge->nodesIterator();
10963       while ( nodeItr->more() )
10964       {
10965         const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10966         if (alreadyCheckedNodes.find(aNode) == alreadyCheckedNodes.end())
10967         {
10968           onside = false;
10969           break;
10970         }
10971       }
10972       if (onside)
10973       {
10974         MESSAGE("    --- edge onside inserted")
10975         theAffectedElems.insert(anEdge);
10976       }
10977     }
10978   }
10979   else
10980   {
10981     const double aTol = Precision::Confusion();
10982     auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10983     auto_ptr<_FaceClassifier>              aFaceClassifier;
10984     if ( theShape.ShapeType() == TopAbs_SOLID )
10985     {
10986       bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10987       bsc3d->PerformInfinitePoint(aTol);
10988     }
10989     else if (theShape.ShapeType() == TopAbs_FACE )
10990     {
10991       aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10992     }
10993
10994     // iterates on indicated elements and get elements by back references from their nodes
10995     TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10996     int ielem;
10997     for ( ielem = 1;  elemItr != theElems.end(); ++elemItr )
10998     {
10999       MESSAGE("element " << ielem++);
11000       SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
11001       if (!anElem)
11002         continue;
11003       SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
11004       while ( nodeItr->more() )
11005       {
11006         MESSAGE("  noeud ");
11007         const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
11008         if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
11009           continue;
11010         SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
11011         while ( backElemItr->more() )
11012         {
11013           MESSAGE("    backelem ");
11014           const SMDS_MeshElement* curElem = backElemItr->next();
11015           if ( curElem && theElems.find(curElem) == theElems.end() &&
11016               ( bsc3d.get() ?
11017                 isInside( curElem, *bsc3d, aTol ) :
11018                 isInside( curElem, *aFaceClassifier, aTol )))
11019             theAffectedElems.insert( curElem );
11020         }
11021       }
11022     }
11023   }
11024   return true;
11025 }
11026
11027 //================================================================================
11028 /*!
11029   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
11030   \param theElems - group of of elements (edges or faces) to be replicated
11031   \param theNodesNot - group of nodes not to replicate
11032   \param theShape - shape to detect affected elements (element which geometric center
11033   located on or inside shape).
11034   The replicated nodes should be associated to affected elements.
11035   \return TRUE if operation has been completed successfully, FALSE otherwise
11036 */
11037 //================================================================================
11038
11039 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
11040                                             const TIDSortedElemSet& theNodesNot,
11041                                             const TopoDS_Shape&     theShape )
11042 {
11043   if ( theShape.IsNull() )
11044     return false;
11045
11046   const double aTol = Precision::Confusion();
11047   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
11048   auto_ptr<_FaceClassifier>              aFaceClassifier;
11049   if ( theShape.ShapeType() == TopAbs_SOLID )
11050   {
11051     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
11052     bsc3d->PerformInfinitePoint(aTol);
11053   }
11054   else if (theShape.ShapeType() == TopAbs_FACE )
11055   {
11056     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
11057   }
11058
11059   // iterates on indicated elements and get elements by back references from their nodes
11060   TIDSortedElemSet anAffected;
11061   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
11062   for ( ;  elemItr != theElems.end(); ++elemItr )
11063   {
11064     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
11065     if (!anElem)
11066       continue;
11067
11068     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
11069     while ( nodeItr->more() )
11070     {
11071       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
11072       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
11073         continue;
11074       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
11075       while ( backElemItr->more() )
11076       {
11077         const SMDS_MeshElement* curElem = backElemItr->next();
11078         if ( curElem && theElems.find(curElem) == theElems.end() &&
11079              ( bsc3d.get() ?
11080                isInside( curElem, *bsc3d, aTol ) :
11081                isInside( curElem, *aFaceClassifier, aTol )))
11082           anAffected.insert( curElem );
11083       }
11084     }
11085   }
11086   return DoubleNodes( theElems, theNodesNot, anAffected );
11087 }
11088
11089 /*!
11090  *  \brief compute an oriented angle between two planes defined by four points.
11091  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
11092  *  @param p0 base of the rotation axe
11093  *  @param p1 extremity of the rotation axe
11094  *  @param g1 belongs to the first plane
11095  *  @param g2 belongs to the second plane
11096  */
11097 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
11098 {
11099 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
11100 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
11101 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
11102 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
11103   gp_Vec vref(p0, p1);
11104   gp_Vec v1(p0, g1);
11105   gp_Vec v2(p0, g2);
11106   gp_Vec n1 = vref.Crossed(v1);
11107   gp_Vec n2 = vref.Crossed(v2);
11108   try {
11109     return n2.AngleWithRef(n1, vref);
11110   }
11111   catch ( Standard_Failure ) {
11112   }
11113   return Max( v1.Magnitude(), v2.Magnitude() );
11114 }
11115
11116 /*!
11117  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
11118  *  The list of groups must contain at least two groups. The groups have to be disjoint: no common element into two different groups.
11119  * The nodes of the internal faces at the boundaries of the groups are doubled. Optionally, the internal faces are replaced by flat elements.
11120  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
11121  * The flat elements are stored in groups of volumes. These groups are named according to the position of the group in the list:
11122  * 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.
11123  * 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.
11124  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
11125  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
11126  * \param theElems - list of groups of volumes, where a group of volume is a set of
11127  *        SMDS_MeshElements sorted by Id.
11128  * \param createJointElems - if TRUE, create the elements
11129  * \param onAllBoundaries - if TRUE, the nodes and elements are also created on
11130  *        the boundary between \a theDomains and the rest mesh
11131  * \return TRUE if operation has been completed successfully, FALSE otherwise
11132  */
11133 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
11134                                                      bool                                 createJointElems,
11135                                                      bool                                 onAllBoundaries)
11136 {
11137   MESSAGE("----------------------------------------------");
11138   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
11139   MESSAGE("----------------------------------------------");
11140
11141   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11142   meshDS->BuildDownWardConnectivity(true);
11143   CHRONO(50);
11144   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
11145
11146   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
11147   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
11148   //     build the list of nodes shared by 2 or more domains, with their domain indexes
11149
11150   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
11151   std::map<int,int>celldom; // cell vtkId --> domain
11152   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
11153   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
11154   faceDomains.clear();
11155   celldom.clear();
11156   cellDomains.clear();
11157   nodeDomains.clear();
11158   std::map<int,int> emptyMap;
11159   std::set<int> emptySet;
11160   emptyMap.clear();
11161
11162   MESSAGE(".. Number of domains :"<<theElems.size());
11163
11164   TIDSortedElemSet theRestDomElems;
11165   const int iRestDom  = -1;
11166   const int idom0     = onAllBoundaries ? iRestDom : 0;
11167   const int nbDomains = theElems.size();
11168
11169   // Check if the domains do not share an element
11170   for (int idom = 0; idom < nbDomains-1; idom++)
11171     {
11172 //       MESSAGE("... Check of domain #" << idom);
11173       const TIDSortedElemSet& domain = theElems[idom];
11174       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11175       for (; elemItr != domain.end(); ++elemItr)
11176         {
11177           const SMDS_MeshElement* anElem = *elemItr;
11178           int idombisdeb = idom + 1 ;
11179           for (int idombis = idombisdeb; idombis < theElems.size(); idombis++) // check if the element belongs to a domain further in the list
11180           {
11181             const TIDSortedElemSet& domainbis = theElems[idombis];
11182             if ( domainbis.count(anElem) )
11183             {
11184               MESSAGE(".... Domain #" << idom);
11185               MESSAGE(".... Domain #" << idombis);
11186               throw SALOME_Exception("The domains are not disjoint.");
11187               return false ;
11188             }
11189           }
11190         }
11191     }
11192
11193   for (int idom = 0; idom < nbDomains; idom++)
11194     {
11195
11196       // --- build a map (face to duplicate --> volume to modify)
11197       //     with all the faces shared by 2 domains (group of elements)
11198       //     and corresponding volume of this domain, for each shared face.
11199       //     a volume has a face shared by 2 domains if it has a neighbor which is not in his domain.
11200
11201       MESSAGE("... Neighbors of domain #" << idom);
11202       const TIDSortedElemSet& domain = theElems[idom];
11203       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11204       for (; elemItr != domain.end(); ++elemItr)
11205         {
11206           const SMDS_MeshElement* anElem = *elemItr;
11207           if (!anElem)
11208             continue;
11209           int vtkId = anElem->getVtkId();
11210           //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
11211           int neighborsVtkIds[NBMAXNEIGHBORS];
11212           int downIds[NBMAXNEIGHBORS];
11213           unsigned char downTypes[NBMAXNEIGHBORS];
11214           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11215           for (int n = 0; n < nbNeighbors; n++)
11216             {
11217               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
11218               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11219               if (elem && ! domain.count(elem)) // neighbor is in another domain : face is shared
11220                 {
11221                   bool ok = false ;
11222                   for (int idombis = 0; idombis < theElems.size() && !ok; idombis++) // check if the neighbor belongs to another domain of the list
11223                   {
11224                     // MESSAGE("Domain " << idombis);
11225                     const TIDSortedElemSet& domainbis = theElems[idombis];
11226                     if ( domainbis.count(elem)) ok = true ; // neighbor is in a correct domain : face is kept
11227                   }
11228                   if ( ok || onAllBoundaries ) // the characteristics of the face is stored
11229                   {
11230                     DownIdType face(downIds[n], downTypes[n]);
11231                     if (!faceDomains[face].count(idom))
11232                       {
11233                         faceDomains[face][idom] = vtkId; // volume associated to face in this domain
11234                         celldom[vtkId] = idom;
11235                         //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
11236                       }
11237                     if ( !ok )
11238                     {
11239                       theRestDomElems.insert( elem );
11240                       faceDomains[face][iRestDom] = neighborsVtkIds[n];
11241                       celldom[neighborsVtkIds[n]] = iRestDom;
11242                     }
11243                   }
11244                 }
11245             }
11246         }
11247     }
11248
11249   //MESSAGE("Number of shared faces " << faceDomains.size());
11250   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
11251
11252   // --- explore the shared faces domain by domain,
11253   //     explore the nodes of the face and see if they belong to a cell in the domain,
11254   //     which has only a node or an edge on the border (not a shared face)
11255
11256   for (int idomain = idom0; idomain < nbDomains; idomain++)
11257     {
11258       //MESSAGE("Domain " << idomain);
11259       const TIDSortedElemSet& domain = (idomain == iRestDom) ? theRestDomElems : theElems[idomain];
11260       itface = faceDomains.begin();
11261       for (; itface != faceDomains.end(); ++itface)
11262         {
11263           const std::map<int, int>& domvol = itface->second;
11264           if (!domvol.count(idomain))
11265             continue;
11266           DownIdType face = itface->first;
11267           //MESSAGE(" --- face " << face.cellId);
11268           std::set<int> oldNodes;
11269           oldNodes.clear();
11270           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11271           std::set<int>::iterator itn = oldNodes.begin();
11272           for (; itn != oldNodes.end(); ++itn)
11273             {
11274               int oldId = *itn;
11275               //MESSAGE("     node " << oldId);
11276               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11277               for (int i=0; i<l.ncells; i++)
11278                 {
11279                   int vtkId = l.cells[i];
11280                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
11281                   if (!domain.count(anElem))
11282                     continue;
11283                   int vtkType = grid->GetCellType(vtkId);
11284                   int downId = grid->CellIdToDownId(vtkId);
11285                   if (downId < 0)
11286                     {
11287                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
11288                       continue; // not OK at this stage of the algorithm:
11289                                 //no cells created after BuildDownWardConnectivity
11290                     }
11291                   DownIdType aCell(downId, vtkType);
11292                   cellDomains[aCell][idomain] = vtkId;
11293                   celldom[vtkId] = idomain;
11294                   //MESSAGE("       cell " << vtkId << " domain " << idomain);
11295                 }
11296             }
11297         }
11298     }
11299
11300   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
11301   //     for each shared face, get the nodes
11302   //     for each node, for each domain of the face, create a clone of the node
11303
11304   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
11305   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
11306   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
11307
11308   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
11309   std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
11310   std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
11311
11312   MESSAGE(".. Duplication of the nodes");
11313   for (int idomain = idom0; idomain < nbDomains; idomain++)
11314     {
11315       itface = faceDomains.begin();
11316       for (; itface != faceDomains.end(); ++itface)
11317         {
11318           const std::map<int, int>& domvol = itface->second;
11319           if (!domvol.count(idomain))
11320             continue;
11321           DownIdType face = itface->first;
11322           //MESSAGE(" --- face " << face.cellId);
11323           std::set<int> oldNodes;
11324           oldNodes.clear();
11325           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11326           std::set<int>::iterator itn = oldNodes.begin();
11327           for (; itn != oldNodes.end(); ++itn)
11328             {
11329               int oldId = *itn;
11330               if (nodeDomains[oldId].empty())
11331                 {
11332                   nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11333                   //MESSAGE("-+-+-b     oldNode " << oldId << " domain " << idomain);
11334                 }
11335               std::map<int, int>::const_iterator itdom = domvol.begin();
11336               for (; itdom != domvol.end(); ++itdom)
11337                 {
11338                   int idom = itdom->first;
11339                   //MESSAGE("         domain " << idom);
11340                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
11341                     {
11342                       if (nodeDomains[oldId].size() >= 2) // a multiple node
11343                         {
11344                           vector<int> orderedDoms;
11345                           //MESSAGE("multiple node " << oldId);
11346                           if (mutipleNodes.count(oldId))
11347                             orderedDoms = mutipleNodes[oldId];
11348                           else
11349                             {
11350                               map<int,int>::iterator it = nodeDomains[oldId].begin();
11351                               for (; it != nodeDomains[oldId].end(); ++it)
11352                                 orderedDoms.push_back(it->first);
11353                             }
11354                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
11355                           //stringstream txt;
11356                           //for (int i=0; i<orderedDoms.size(); i++)
11357                           //  txt << orderedDoms[i] << " ";
11358                           //MESSAGE("orderedDoms " << txt.str());
11359                           mutipleNodes[oldId] = orderedDoms;
11360                         }
11361                       double *coords = grid->GetPoint(oldId);
11362                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11363                       copyPosition( meshDS->FindNodeVtk( oldId ), newNode );
11364                       int newId = newNode->getVtkId();
11365                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
11366                       //MESSAGE("-+-+-c     oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
11367                     }
11368                 }
11369             }
11370         }
11371     }
11372
11373   MESSAGE(".. Creation of elements");
11374   for (int idomain = idom0; idomain < nbDomains; idomain++)
11375     {
11376       itface = faceDomains.begin();
11377       for (; itface != faceDomains.end(); ++itface)
11378         {
11379           std::map<int, int> domvol = itface->second;
11380           if (!domvol.count(idomain))
11381             continue;
11382           DownIdType face = itface->first;
11383           //MESSAGE(" --- face " << face.cellId);
11384           std::set<int> oldNodes;
11385           oldNodes.clear();
11386           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11387           int nbMultipleNodes = 0;
11388           std::set<int>::iterator itn = oldNodes.begin();
11389           for (; itn != oldNodes.end(); ++itn)
11390             {
11391               int oldId = *itn;
11392               if (mutipleNodes.count(oldId))
11393                 nbMultipleNodes++;
11394             }
11395           if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains
11396             {
11397               //MESSAGE("multiple Nodes detected on a shared face");
11398               int downId = itface->first.cellId;
11399               unsigned char cellType = itface->first.cellType;
11400               // --- shared edge or shared face ?
11401               if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
11402                 {
11403                   int nodes[3];
11404                   int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
11405                   for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
11406                     if (mutipleNodes.count(nodes[i]))
11407                       if (!mutipleNodesToFace.count(nodes[i]))
11408                         mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
11409                 }
11410               else // shared face (between two volumes)
11411                 {
11412                   int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11413                   const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11414                   const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11415                   for (int ie =0; ie < nbEdges; ie++)
11416                     {
11417                       int nodes[3];
11418                       int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11419                       if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11420                         {
11421                           vector<int> vn0 = mutipleNodes[nodes[0]];
11422                           vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11423                           vector<int> doms;
11424                           for (int i0 = 0; i0 < vn0.size(); i0++)
11425                             for (int i1 = 0; i1 < vn1.size(); i1++)
11426                               if (vn0[i0] == vn1[i1])
11427                                 doms.push_back(vn0[i0]);
11428                           if (doms.size() >2)
11429                             {
11430                               //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11431                               double *coords = grid->GetPoint(nodes[0]);
11432                               gp_Pnt p0(coords[0], coords[1], coords[2]);
11433                               coords = grid->GetPoint(nodes[nbNodes - 1]);
11434                               gp_Pnt p1(coords[0], coords[1], coords[2]);
11435                               gp_Pnt gref;
11436                               int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11437                               map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11438                               map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11439                               int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11440                               for (int id=0; id < doms.size(); id++)
11441                                 {
11442                                   int idom = doms[id];
11443                                   const TIDSortedElemSet& domain = (idom == iRestDom) ? theRestDomElems : theElems[idom];
11444                                   for (int ivol=0; ivol<nbvol; ivol++)
11445                                     {
11446                                       int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11447                                       SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11448                                       if (domain.count(elem))
11449                                         {
11450                                           SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11451                                           domvol[idom] = svol;
11452                                           //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11453                                           double values[3];
11454                                           vtkIdType npts = 0;
11455                                           vtkIdType* pts = 0;
11456                                           grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11457                                           SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11458                                           if (id ==0)
11459                                             {
11460                                               gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11461                                               angleDom[idom] = 0;
11462                                             }
11463                                           else
11464                                             {
11465                                               gp_Pnt g(values[0], values[1], values[2]);
11466                                               angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11467                                               //MESSAGE("  angle=" << angleDom[idom]);
11468                                             }
11469                                           break;
11470                                         }
11471                                     }
11472                                 }
11473                               map<double, int> sortedDom; // sort domains by angle
11474                               for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11475                                 sortedDom[ia->second] = ia->first;
11476                               vector<int> vnodes;
11477                               vector<int> vdom;
11478                               for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11479                                 {
11480                                   vdom.push_back(ib->second);
11481                                   //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11482                                 }
11483                               for (int ino = 0; ino < nbNodes; ino++)
11484                                 vnodes.push_back(nodes[ino]);
11485                               edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11486                             }
11487                         }
11488                     }
11489                 }
11490             }
11491         }
11492     }
11493
11494   // --- iterate on shared faces (volumes to modify, face to extrude)
11495   //     get node id's of the face (id SMDS = id VTK)
11496   //     create flat element with old and new nodes if requested
11497
11498   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11499   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11500
11501   std::map<int, std::map<long,int> > nodeQuadDomains;
11502   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11503
11504   MESSAGE(".. Creation of elements: simple junction");
11505   if (createJointElems)
11506     {
11507       int idg;
11508       string joints2DName = "joints2D";
11509       mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg);
11510       SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
11511       string joints3DName = "joints3D";
11512       mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg);
11513       SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
11514
11515       itface = faceDomains.begin();
11516       for (; itface != faceDomains.end(); ++itface)
11517         {
11518           DownIdType face = itface->first;
11519           std::set<int> oldNodes;
11520           std::set<int>::iterator itn;
11521           oldNodes.clear();
11522           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11523
11524           std::map<int, int> domvol = itface->second;
11525           std::map<int, int>::iterator itdom = domvol.begin();
11526           int dom1 = itdom->first;
11527           int vtkVolId = itdom->second;
11528           itdom++;
11529           int dom2 = itdom->first;
11530           SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11531                                                              nodeQuadDomains);
11532           stringstream grpname;
11533           grpname << "j_";
11534           if (dom1 < dom2)
11535             grpname << dom1 << "_" << dom2;
11536           else
11537             grpname << dom2 << "_" << dom1;
11538           string namegrp = grpname.str();
11539           if (!mapOfJunctionGroups.count(namegrp))
11540             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
11541           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11542           if (sgrp)
11543             sgrp->Add(vol->GetID());
11544           if (vol->GetType() == SMDSAbs_Volume)
11545             joints3DGrp->Add(vol->GetID());
11546           else if (vol->GetType() == SMDSAbs_Face)
11547             joints2DGrp->Add(vol->GetID());
11548         }
11549     }
11550
11551   // --- create volumes on multiple domain intersection if requested
11552   //     iterate on mutipleNodesToFace
11553   //     iterate on edgesMultiDomains
11554
11555   MESSAGE(".. Creation of elements: multiple junction");
11556   if (createJointElems)
11557     {
11558       // --- iterate on mutipleNodesToFace
11559
11560       std::map<int, std::vector<int> >::iterator itn =  mutipleNodesToFace.begin();
11561       for (; itn != mutipleNodesToFace.end(); ++itn)
11562         {
11563           int node = itn->first;
11564           vector<int> orderDom = itn->second;
11565           vector<vtkIdType> orderedNodes;
11566           for (int idom = 0; idom <orderDom.size(); idom++)
11567             orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
11568             SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
11569
11570             stringstream grpname;
11571             grpname << "m2j_";
11572             grpname << 0 << "_" << 0;
11573             int idg;
11574             string namegrp = grpname.str();
11575             if (!mapOfJunctionGroups.count(namegrp))
11576               mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
11577             SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11578             if (sgrp)
11579               sgrp->Add(face->GetID());
11580         }
11581
11582       // --- iterate on edgesMultiDomains
11583
11584       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11585       for (; ite != edgesMultiDomains.end(); ++ite)
11586         {
11587           vector<int> nodes = ite->first;
11588           vector<int> orderDom = ite->second;
11589           vector<vtkIdType> orderedNodes;
11590           if (nodes.size() == 2)
11591             {
11592               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11593               for (int ino=0; ino < nodes.size(); ino++)
11594                 if (orderDom.size() == 3)
11595                   for (int idom = 0; idom <orderDom.size(); idom++)
11596                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11597                 else
11598                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11599                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11600               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11601
11602               int idg;
11603               string namegrp = "jointsMultiples";
11604               if (!mapOfJunctionGroups.count(namegrp))
11605                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11606               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11607               if (sgrp)
11608                 sgrp->Add(vol->GetID());
11609             }
11610           else
11611             {
11612               INFOS("Quadratic multiple joints not implemented");
11613               // TODO quadratic nodes
11614             }
11615         }
11616     }
11617
11618   // --- list the explicit faces and edges of the mesh that need to be modified,
11619   //     i.e. faces and edges built with one or more duplicated nodes.
11620   //     associate these faces or edges to their corresponding domain.
11621   //     only the first domain found is kept when a face or edge is shared
11622
11623   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11624   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11625   faceOrEdgeDom.clear();
11626   feDom.clear();
11627
11628   MESSAGE(".. Modification of elements");
11629   for (int idomain = idom0; idomain < nbDomains; idomain++)
11630     {
11631       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11632       for (; itnod != nodeDomains.end(); ++itnod)
11633         {
11634           int oldId = itnod->first;
11635           //MESSAGE("     node " << oldId);
11636           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11637           for (int i = 0; i < l.ncells; i++)
11638             {
11639               int vtkId = l.cells[i];
11640               int vtkType = grid->GetCellType(vtkId);
11641               int downId = grid->CellIdToDownId(vtkId);
11642               if (downId < 0)
11643                 continue; // new cells: not to be modified
11644               DownIdType aCell(downId, vtkType);
11645               int volParents[1000];
11646               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11647               for (int j = 0; j < nbvol; j++)
11648                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11649                   if (!feDom.count(vtkId))
11650                     {
11651                       feDom[vtkId] = idomain;
11652                       faceOrEdgeDom[aCell] = emptyMap;
11653                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11654                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11655                       //        << " type " << vtkType << " downId " << downId);
11656                     }
11657             }
11658         }
11659     }
11660
11661   // --- iterate on shared faces (volumes to modify, face to extrude)
11662   //     get node id's of the face
11663   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11664
11665   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11666   for (int m=0; m<3; m++)
11667     {
11668       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11669       itface = (*amap).begin();
11670       for (; itface != (*amap).end(); ++itface)
11671         {
11672           DownIdType face = itface->first;
11673           std::set<int> oldNodes;
11674           std::set<int>::iterator itn;
11675           oldNodes.clear();
11676           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11677           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11678           std::map<int, int> localClonedNodeIds;
11679
11680           std::map<int, int> domvol = itface->second;
11681           std::map<int, int>::iterator itdom = domvol.begin();
11682           for (; itdom != domvol.end(); ++itdom)
11683             {
11684               int idom = itdom->first;
11685               int vtkVolId = itdom->second;
11686               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11687               localClonedNodeIds.clear();
11688               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11689                 {
11690                   int oldId = *itn;
11691                   if (nodeDomains[oldId].count(idom))
11692                     {
11693                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11694                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11695                     }
11696                 }
11697               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11698             }
11699         }
11700     }
11701
11702   // Remove empty groups (issue 0022812)
11703   std::map<std::string, SMESH_Group*>::iterator name_group = mapOfJunctionGroups.begin();
11704   for ( ; name_group != mapOfJunctionGroups.end(); ++name_group )
11705   {
11706     if ( name_group->second && name_group->second->GetGroupDS()->IsEmpty() )
11707       myMesh->RemoveGroup( name_group->second->GetGroupDS()->GetID() );
11708   }
11709
11710   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11711   grid->BuildLinks();
11712
11713   CHRONOSTOP(50);
11714   counters::stats();
11715   return true;
11716 }
11717
11718 /*!
11719  * \brief Double nodes on some external faces and create flat elements.
11720  * Flat elements are mainly used by some types of mechanic calculations.
11721  *
11722  * Each group of the list must be constituted of faces.
11723  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11724  * @param theElems - list of groups of faces, where a group of faces is a set of
11725  * SMDS_MeshElements sorted by Id.
11726  * @return TRUE if operation has been completed successfully, FALSE otherwise
11727  */
11728 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11729 {
11730   MESSAGE("-------------------------------------------------");
11731   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11732   MESSAGE("-------------------------------------------------");
11733
11734   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11735
11736   // --- For each group of faces
11737   //     duplicate the nodes, create a flat element based on the face
11738   //     replace the nodes of the faces by their clones
11739
11740   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11741   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11742   clonedNodes.clear();
11743   intermediateNodes.clear();
11744   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11745   mapOfJunctionGroups.clear();
11746
11747   for (int idom = 0; idom < theElems.size(); idom++)
11748     {
11749       const TIDSortedElemSet& domain = theElems[idom];
11750       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11751       for (; elemItr != domain.end(); ++elemItr)
11752         {
11753           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11754           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11755           if (!aFace)
11756             continue;
11757           // MESSAGE("aFace=" << aFace->GetID());
11758           bool isQuad = aFace->IsQuadratic();
11759           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11760
11761           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11762
11763           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11764           while (nodeIt->more())
11765             {
11766               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11767               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11768               if (isMedium)
11769                 ln2.push_back(node);
11770               else
11771                 ln0.push_back(node);
11772
11773               const SMDS_MeshNode* clone = 0;
11774               if (!clonedNodes.count(node))
11775                 {
11776                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11777                   copyPosition( node, clone );
11778                   clonedNodes[node] = clone;
11779                 }
11780               else
11781                 clone = clonedNodes[node];
11782
11783               if (isMedium)
11784                 ln3.push_back(clone);
11785               else
11786                 ln1.push_back(clone);
11787
11788               const SMDS_MeshNode* inter = 0;
11789               if (isQuad && (!isMedium))
11790                 {
11791                   if (!intermediateNodes.count(node))
11792                     {
11793                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11794                       copyPosition( node, inter );
11795                       intermediateNodes[node] = inter;
11796                     }
11797                   else
11798                     inter = intermediateNodes[node];
11799                   ln4.push_back(inter);
11800                 }
11801             }
11802
11803           // --- extrude the face
11804
11805           vector<const SMDS_MeshNode*> ln;
11806           SMDS_MeshVolume* vol = 0;
11807           vtkIdType aType = aFace->GetVtkType();
11808           switch (aType)
11809           {
11810             case VTK_TRIANGLE:
11811               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11812               // MESSAGE("vol prism " << vol->GetID());
11813               ln.push_back(ln1[0]);
11814               ln.push_back(ln1[1]);
11815               ln.push_back(ln1[2]);
11816               break;
11817             case VTK_QUAD:
11818               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11819               // MESSAGE("vol hexa " << vol->GetID());
11820               ln.push_back(ln1[0]);
11821               ln.push_back(ln1[1]);
11822               ln.push_back(ln1[2]);
11823               ln.push_back(ln1[3]);
11824               break;
11825             case VTK_QUADRATIC_TRIANGLE:
11826               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11827                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11828               // MESSAGE("vol quad prism " << vol->GetID());
11829               ln.push_back(ln1[0]);
11830               ln.push_back(ln1[1]);
11831               ln.push_back(ln1[2]);
11832               ln.push_back(ln3[0]);
11833               ln.push_back(ln3[1]);
11834               ln.push_back(ln3[2]);
11835               break;
11836             case VTK_QUADRATIC_QUAD:
11837 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11838 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11839 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11840               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11841                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11842                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11843               // MESSAGE("vol quad hexa " << vol->GetID());
11844               ln.push_back(ln1[0]);
11845               ln.push_back(ln1[1]);
11846               ln.push_back(ln1[2]);
11847               ln.push_back(ln1[3]);
11848               ln.push_back(ln3[0]);
11849               ln.push_back(ln3[1]);
11850               ln.push_back(ln3[2]);
11851               ln.push_back(ln3[3]);
11852               break;
11853             case VTK_POLYGON:
11854               break;
11855             default:
11856               break;
11857           }
11858
11859           if (vol)
11860             {
11861               stringstream grpname;
11862               grpname << "jf_";
11863               grpname << idom;
11864               int idg;
11865               string namegrp = grpname.str();
11866               if (!mapOfJunctionGroups.count(namegrp))
11867                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11868               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11869               if (sgrp)
11870                 sgrp->Add(vol->GetID());
11871             }
11872
11873           // --- modify the face
11874
11875           aFace->ChangeNodes(&ln[0], ln.size());
11876         }
11877     }
11878   return true;
11879 }
11880
11881 /*!
11882  *  \brief identify all the elements around a geom shape, get the faces delimiting the hole
11883  *  Build groups of volume to remove, groups of faces to replace on the skin of the object,
11884  *  groups of faces to remove inside the object, (idem edges).
11885  *  Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape)
11886  */
11887 void SMESH_MeshEditor::CreateHoleSkin(double radius,
11888                                       const TopoDS_Shape& theShape,
11889                                       SMESH_NodeSearcher* theNodeSearcher,
11890                                       const char* groupName,
11891                                       std::vector<double>&   nodesCoords,
11892                                       std::vector<std::vector<int> >& listOfListOfNodes)
11893 {
11894   MESSAGE("--------------------------------");
11895   MESSAGE("SMESH_MeshEditor::CreateHoleSkin");
11896   MESSAGE("--------------------------------");
11897
11898   // --- zone of volumes to remove is given :
11899   //     1 either by a geom shape (one or more vertices) and a radius,
11900   //     2 either by a group of nodes (representative of the shape)to use with the radius,
11901   //     3 either by a group of nodes where all the elements build on one of this nodes are to remove,
11902   //     In the case 2, the group of nodes is an external group of nodes from another mesh,
11903   //     In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter),
11904   //     defined by it's name.
11905
11906   SMESHDS_GroupBase* groupDS = 0;
11907   SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups();
11908   while ( groupIt->more() )
11909     {
11910       groupDS = 0;
11911       SMESH_Group * group = groupIt->next();
11912       if ( !group ) continue;
11913       groupDS = group->GetGroupDS();
11914       if ( !groupDS || groupDS->IsEmpty() ) continue;
11915       std::string grpName = group->GetName();
11916       //MESSAGE("grpName=" << grpName);
11917       if (grpName == groupName)
11918         break;
11919       else
11920         groupDS = 0;
11921     }
11922
11923   bool isNodeGroup = false;
11924   bool isNodeCoords = false;
11925   if (groupDS)
11926     {
11927       if (groupDS->GetType() != SMDSAbs_Node)
11928         return;
11929       isNodeGroup = true;     // a group of nodes exists and it is in this mesh
11930     }
11931
11932   if (nodesCoords.size() > 0)
11933     isNodeCoords = true; // a list o nodes given by their coordinates
11934   //MESSAGE("---" << isNodeGroup << " " << isNodeCoords);
11935
11936   // --- define groups to build
11937
11938   int idg; // --- group of SMDS volumes
11939   string grpvName = groupName;
11940   grpvName += "_vol";
11941   SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
11942   if (!grp)
11943     {
11944       MESSAGE("group not created " << grpvName);
11945       return;
11946     }
11947   SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
11948
11949   int idgs; // --- group of SMDS faces on the skin
11950   string grpsName = groupName;
11951   grpsName += "_skin";
11952   SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
11953   if (!grps)
11954     {
11955       MESSAGE("group not created " << grpsName);
11956       return;
11957     }
11958   SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
11959
11960   int idgi; // --- group of SMDS faces internal (several shapes)
11961   string grpiName = groupName;
11962   grpiName += "_internalFaces";
11963   SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
11964   if (!grpi)
11965     {
11966       MESSAGE("group not created " << grpiName);
11967       return;
11968     }
11969   SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
11970
11971   int idgei; // --- group of SMDS faces internal (several shapes)
11972   string grpeiName = groupName;
11973   grpeiName += "_internalEdges";
11974   SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
11975   if (!grpei)
11976     {
11977       MESSAGE("group not created " << grpeiName);
11978       return;
11979     }
11980   SMESHDS_Group *sgrpei = dynamic_cast<SMESHDS_Group*>(grpei->GetGroupDS());
11981
11982   // --- build downward connectivity
11983
11984   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11985   meshDS->BuildDownWardConnectivity(true);
11986   SMDS_UnstructuredGrid* grid = meshDS->getGrid();
11987
11988   // --- set of volumes detected inside
11989
11990   std::set<int> setOfInsideVol;
11991   std::set<int> setOfVolToCheck;
11992
11993   std::vector<gp_Pnt> gpnts;
11994   gpnts.clear();
11995
11996   if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
11997     {
11998       MESSAGE("group of nodes provided");
11999       SMDS_ElemIteratorPtr elemIt = groupDS->GetElements();
12000       while ( elemIt->more() )
12001         {
12002           const SMDS_MeshElement* elem = elemIt->next();
12003           if (!elem)
12004             continue;
12005           const SMDS_MeshNode* node = dynamic_cast<const SMDS_MeshNode*>(elem);
12006           if (!node)
12007             continue;
12008           SMDS_MeshElement* vol = 0;
12009           SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume);
12010           while (volItr->more())
12011             {
12012               vol = (SMDS_MeshElement*)volItr->next();
12013               setOfInsideVol.insert(vol->getVtkId());
12014               sgrp->Add(vol->GetID());
12015             }
12016         }
12017     }
12018   else if (isNodeCoords)
12019     {
12020       MESSAGE("list of nodes coordinates provided");
12021       int i = 0;
12022       int k = 0;
12023       while (i < nodesCoords.size()-2)
12024         {
12025           double x = nodesCoords[i++];
12026           double y = nodesCoords[i++];
12027           double z = nodesCoords[i++];
12028           gp_Pnt p = gp_Pnt(x, y ,z);
12029           gpnts.push_back(p);
12030           MESSAGE("TopoDS_Vertex " << k << " " << p.X() << " " << p.Y() << " " << p.Z());
12031           k++;
12032         }
12033     }
12034   else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius
12035     {
12036       MESSAGE("no group of nodes provided, using vertices from geom shape, and radius");
12037       TopTools_IndexedMapOfShape vertexMap;
12038       TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap );
12039       gp_Pnt p = gp_Pnt(0,0,0);
12040       if (vertexMap.Extent() < 1)
12041         return;
12042
12043       for ( int i = 1; i <= vertexMap.Extent(); ++i )
12044         {
12045           const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i ));
12046           p = BRep_Tool::Pnt(vertex);
12047           gpnts.push_back(p);
12048           MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z());
12049         }
12050     }
12051
12052   if (gpnts.size() > 0)
12053     {
12054       int nodeId = 0;
12055       const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
12056       if (startNode)
12057         nodeId = startNode->GetID();
12058       MESSAGE("nodeId " << nodeId);
12059
12060       double radius2 = radius*radius;
12061       MESSAGE("radius2 " << radius2);
12062
12063       // --- volumes on start node
12064
12065       setOfVolToCheck.clear();
12066       SMDS_MeshElement* startVol = 0;
12067       SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
12068       while (volItr->more())
12069         {
12070           startVol = (SMDS_MeshElement*)volItr->next();
12071           setOfVolToCheck.insert(startVol->getVtkId());
12072         }
12073       if (setOfVolToCheck.empty())
12074         {
12075           MESSAGE("No volumes found");
12076           return;
12077         }
12078
12079       // --- starting with central volumes then their neighbors, check if they are inside
12080       //     or outside the domain, until no more new neighbor volume is inside.
12081       //     Fill the group of inside volumes
12082
12083       std::map<int, double> mapOfNodeDistance2;
12084       mapOfNodeDistance2.clear();
12085       std::set<int> setOfOutsideVol;
12086       while (!setOfVolToCheck.empty())
12087         {
12088           std::set<int>::iterator it = setOfVolToCheck.begin();
12089           int vtkId = *it;
12090           MESSAGE("volume to check,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12091           bool volInside = false;
12092           vtkIdType npts = 0;
12093           vtkIdType* pts = 0;
12094           grid->GetCellPoints(vtkId, npts, pts);
12095           for (int i=0; i<npts; i++)
12096             {
12097               double distance2 = 0;
12098               if (mapOfNodeDistance2.count(pts[i]))
12099                 {
12100                   distance2 = mapOfNodeDistance2[pts[i]];
12101                   MESSAGE("point " << pts[i] << " distance2 " << distance2);
12102                 }
12103               else
12104                 {
12105                   double *coords = grid->GetPoint(pts[i]);
12106                   gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
12107                   distance2 = 1.E40;
12108                   for (int j=0; j<gpnts.size(); j++)
12109                     {
12110                       double d2 = aPoint.SquareDistance(gpnts[j]);
12111                       if (d2 < distance2)
12112                         {
12113                           distance2 = d2;
12114                           if (distance2 < radius2)
12115                             break;
12116                         }
12117                     }
12118                   mapOfNodeDistance2[pts[i]] = distance2;
12119                   MESSAGE("  point "  << pts[i]  << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " <<  coords[2]);
12120                 }
12121               if (distance2 < radius2)
12122                 {
12123                   volInside = true; // one or more nodes inside the domain
12124                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
12125                   break;
12126                 }
12127             }
12128           if (volInside)
12129             {
12130               setOfInsideVol.insert(vtkId);
12131               MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12132               int neighborsVtkIds[NBMAXNEIGHBORS];
12133               int downIds[NBMAXNEIGHBORS];
12134               unsigned char downTypes[NBMAXNEIGHBORS];
12135               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12136               for (int n = 0; n < nbNeighbors; n++)
12137                 if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n]))
12138                   setOfVolToCheck.insert(neighborsVtkIds[n]);
12139             }
12140           else
12141             {
12142               setOfOutsideVol.insert(vtkId);
12143               MESSAGE("  volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12144             }
12145           setOfVolToCheck.erase(vtkId);
12146         }
12147     }
12148
12149   // --- for outside hexahedrons, check if they have more than one neighbor volume inside
12150   //     If yes, add the volume to the inside set
12151
12152   bool addedInside = true;
12153   std::set<int> setOfVolToReCheck;
12154   while (addedInside)
12155     {
12156       MESSAGE(" --------------------------- re check");
12157       addedInside = false;
12158       std::set<int>::iterator itv = setOfInsideVol.begin();
12159       for (; itv != setOfInsideVol.end(); ++itv)
12160         {
12161           int vtkId = *itv;
12162           int neighborsVtkIds[NBMAXNEIGHBORS];
12163           int downIds[NBMAXNEIGHBORS];
12164           unsigned char downTypes[NBMAXNEIGHBORS];
12165           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12166           for (int n = 0; n < nbNeighbors; n++)
12167             if (!setOfInsideVol.count(neighborsVtkIds[n]))
12168               setOfVolToReCheck.insert(neighborsVtkIds[n]);
12169         }
12170       setOfVolToCheck = setOfVolToReCheck;
12171       setOfVolToReCheck.clear();
12172       while  (!setOfVolToCheck.empty())
12173         {
12174           std::set<int>::iterator it = setOfVolToCheck.begin();
12175           int vtkId = *it;
12176           if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON)
12177             {
12178               MESSAGE("volume to recheck,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12179               int countInside = 0;
12180               int neighborsVtkIds[NBMAXNEIGHBORS];
12181               int downIds[NBMAXNEIGHBORS];
12182               unsigned char downTypes[NBMAXNEIGHBORS];
12183               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12184               for (int n = 0; n < nbNeighbors; n++)
12185                 if (setOfInsideVol.count(neighborsVtkIds[n]))
12186                   countInside++;
12187               MESSAGE("countInside " << countInside);
12188               if (countInside > 1)
12189                 {
12190                   MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12191                   setOfInsideVol.insert(vtkId);
12192                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
12193                   addedInside = true;
12194                 }
12195               else
12196                 setOfVolToReCheck.insert(vtkId);
12197             }
12198           setOfVolToCheck.erase(vtkId);
12199         }
12200     }
12201
12202   // --- map of Downward faces at the boundary, inside the global volume
12203   //     map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin)
12204   //     fill group of SMDS faces inside the volume (when several volume shapes)
12205   //     fill group of SMDS faces on the skin of the global volume (if skin)
12206
12207   std::map<DownIdType, int, DownIdCompare> boundaryFaces; // boundary faces inside the volume --> corresponding cell
12208   std::map<DownIdType, int, DownIdCompare> skinFaces;     // faces on the skin of the global volume --> corresponding cell
12209   std::set<int>::iterator it = setOfInsideVol.begin();
12210   for (; it != setOfInsideVol.end(); ++it)
12211     {
12212       int vtkId = *it;
12213       //MESSAGE("  vtkId " << vtkId  << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12214       int neighborsVtkIds[NBMAXNEIGHBORS];
12215       int downIds[NBMAXNEIGHBORS];
12216       unsigned char downTypes[NBMAXNEIGHBORS];
12217       int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true);
12218       for (int n = 0; n < nbNeighbors; n++)
12219         {
12220           int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n]));
12221           if (neighborDim == 3)
12222             {
12223               if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary
12224                 {
12225                   DownIdType face(downIds[n], downTypes[n]);
12226                   boundaryFaces[face] = vtkId;
12227                 }
12228               // if the face between to volumes is in the mesh, get it (internal face between shapes)
12229               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
12230               if (vtkFaceId >= 0)
12231                 {
12232                   sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId));
12233                   // find also the smds edges on this face
12234                   int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]);
12235                   const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]);
12236                   const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]);
12237                   for (int i = 0; i < nbEdges; i++)
12238                     {
12239                       int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]);
12240                       if (vtkEdgeId >= 0)
12241                         sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId));
12242                     }
12243                 }
12244             }
12245           else if (neighborDim == 2) // skin of the volume
12246             {
12247               DownIdType face(downIds[n], downTypes[n]);
12248               skinFaces[face] = vtkId;
12249               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
12250               if (vtkFaceId >= 0)
12251                 sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId));
12252             }
12253         }
12254     }
12255
12256   // --- identify the edges constituting the wire of each subshape on the skin
12257   //     define polylines with the nodes of edges, equivalent to wires
12258   //     project polylines on subshapes, and partition, to get geom faces
12259
12260   std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
12261   std::set<int> emptySet;
12262   emptySet.clear();
12263   std::set<int> shapeIds;
12264
12265   SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
12266   while (itelem->more())
12267     {
12268       const SMDS_MeshElement *elem = itelem->next();
12269       int shapeId = elem->getshapeId();
12270       int vtkId = elem->getVtkId();
12271       if (!shapeIdToVtkIdSet.count(shapeId))
12272         {
12273           shapeIdToVtkIdSet[shapeId] = emptySet;
12274           shapeIds.insert(shapeId);
12275         }
12276       shapeIdToVtkIdSet[shapeId].insert(vtkId);
12277     }
12278
12279   std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
12280   std::set<DownIdType, DownIdCompare> emptyEdges;
12281   emptyEdges.clear();
12282
12283   std::map<int, std::set<int> >::iterator itShape =  shapeIdToVtkIdSet.begin();
12284   for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
12285     {
12286       int shapeId = itShape->first;
12287       MESSAGE(" --- Shape ID --- "<< shapeId);
12288       shapeIdToEdges[shapeId] = emptyEdges;
12289
12290       std::vector<int> nodesEdges;
12291
12292       std::set<int>::iterator its = itShape->second.begin();
12293       for (; its != itShape->second.end(); ++its)
12294         {
12295           int vtkId = *its;
12296           MESSAGE("     " << vtkId);
12297           int neighborsVtkIds[NBMAXNEIGHBORS];
12298           int downIds[NBMAXNEIGHBORS];
12299           unsigned char downTypes[NBMAXNEIGHBORS];
12300           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12301           for (int n = 0; n < nbNeighbors; n++)
12302             {
12303               if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
12304                 continue;
12305               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
12306               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
12307               if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
12308                 {
12309                   DownIdType edge(downIds[n], downTypes[n]);
12310                   if (!shapeIdToEdges[shapeId].count(edge))
12311                     {
12312                       shapeIdToEdges[shapeId].insert(edge);
12313                       int vtkNodeId[3];
12314                       int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId);
12315                       nodesEdges.push_back(vtkNodeId[0]);
12316                       nodesEdges.push_back(vtkNodeId[nbNodes-1]);
12317                       MESSAGE("       --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1);
12318                     }
12319                 }
12320             }
12321         }
12322
12323       std::list<int> order;
12324       order.clear();
12325       if (nodesEdges.size() > 0)
12326         {
12327           order.push_back(nodesEdges[0]); MESSAGE("       --- back " << order.back()+1); // SMDS id = VTK id + 1;
12328           nodesEdges[0] = -1;
12329           order.push_back(nodesEdges[1]); MESSAGE("       --- back " << order.back()+1);
12330           nodesEdges[1] = -1; // do not reuse this edge
12331           bool found = true;
12332           while (found)
12333             {
12334               int nodeTofind = order.back(); // try first to push back
12335               int i = 0;
12336               for (i = 0; i<nodesEdges.size(); i++)
12337                 if (nodesEdges[i] == nodeTofind)
12338                   break;
12339               if (i == nodesEdges.size())
12340                 found = false; // no follower found on back
12341               else
12342                 {
12343                   if (i%2) // odd ==> use the previous one
12344                     if (nodesEdges[i-1] < 0)
12345                       found = false;
12346                     else
12347                       {
12348                         order.push_back(nodesEdges[i-1]); MESSAGE("       --- back " << order.back()+1);
12349                         nodesEdges[i-1] = -1;
12350                       }
12351                   else // even ==> use the next one
12352                     if (nodesEdges[i+1] < 0)
12353                       found = false;
12354                     else
12355                       {
12356                         order.push_back(nodesEdges[i+1]); MESSAGE("       --- back " << order.back()+1);
12357                         nodesEdges[i+1] = -1;
12358                       }
12359                 }
12360               if (found)
12361                 continue;
12362               // try to push front
12363               found = true;
12364               nodeTofind = order.front(); // try to push front
12365               for (i = 0; i<nodesEdges.size(); i++)
12366                 if (nodesEdges[i] == nodeTofind)
12367                   break;
12368               if (i == nodesEdges.size())
12369                 {
12370                   found = false; // no predecessor found on front
12371                   continue;
12372                 }
12373               if (i%2) // odd ==> use the previous one
12374                 if (nodesEdges[i-1] < 0)
12375                   found = false;
12376                 else
12377                   {
12378                     order.push_front(nodesEdges[i-1]); MESSAGE("       --- front " << order.front()+1);
12379                     nodesEdges[i-1] = -1;
12380                   }
12381               else // even ==> use the next one
12382                 if (nodesEdges[i+1] < 0)
12383                   found = false;
12384                 else
12385                   {
12386                     order.push_front(nodesEdges[i+1]); MESSAGE("       --- front " << order.front()+1);
12387                     nodesEdges[i+1] = -1;
12388                   }
12389             }
12390         }
12391
12392
12393       std::vector<int> nodes;
12394       nodes.push_back(shapeId);
12395       std::list<int>::iterator itl = order.begin();
12396       for (; itl != order.end(); itl++)
12397         {
12398           nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
12399           MESSAGE("              ordered node " << nodes[nodes.size()-1]);
12400         }
12401       listOfListOfNodes.push_back(nodes);
12402     }
12403
12404   //     partition geom faces with blocFissure
12405   //     mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose)
12406   //     mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose)
12407
12408   return;
12409 }
12410
12411
12412 //================================================================================
12413 /*!
12414  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
12415  * The created 2D mesh elements based on nodes of free faces of boundary volumes
12416  * \return TRUE if operation has been completed successfully, FALSE otherwise
12417  */
12418 //================================================================================
12419
12420 bool SMESH_MeshEditor::Make2DMeshFrom3D()
12421 {
12422   // iterates on volume elements and detect all free faces on them
12423   SMESHDS_Mesh* aMesh = GetMeshDS();
12424   if (!aMesh)
12425     return false;
12426
12427   ElemFeatures faceType( SMDSAbs_Face );
12428   int nbFree = 0, nbExisted = 0, nbCreated = 0;
12429   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
12430   while(vIt->more())
12431   {
12432     const SMDS_MeshVolume* volume = vIt->next();
12433     SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
12434     vTool.SetExternalNormal();
12435     const int iQuad = volume->IsQuadratic();
12436     faceType.SetQuad( iQuad );
12437     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
12438     {
12439       if (!vTool.IsFreeFace(iface))
12440         continue;
12441       nbFree++;
12442       vector<const SMDS_MeshNode *> nodes;
12443       int nbFaceNodes = vTool.NbFaceNodes(iface);
12444       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
12445       int inode = 0;
12446       for ( ; inode < nbFaceNodes; inode += iQuad+1)
12447         nodes.push_back(faceNodes[inode]);
12448
12449       if (iQuad) // add medium nodes
12450       {
12451         for ( inode = 1; inode < nbFaceNodes; inode += 2)
12452           nodes.push_back(faceNodes[inode]);
12453         if ( nbFaceNodes == 9 ) // bi-quadratic quad
12454           nodes.push_back(faceNodes[8]);
12455       }
12456       // add new face based on volume nodes
12457       if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) )
12458       {
12459         nbExisted++; // face already exsist
12460       }
12461       else
12462       {
12463         AddElement( nodes, faceType.SetPoly( nbFaceNodes/(iQuad+1) > 4 ));
12464         nbCreated++;
12465       }
12466     }
12467   }
12468   return ( nbFree == ( nbExisted + nbCreated ));
12469 }
12470
12471 namespace
12472 {
12473   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
12474   {
12475     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
12476       return n;
12477     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
12478   }
12479 }
12480 //================================================================================
12481 /*!
12482  * \brief Creates missing boundary elements
12483  *  \param elements - elements whose boundary is to be checked
12484  *  \param dimension - defines type of boundary elements to create
12485  *  \param group - a group to store created boundary elements in
12486  *  \param targetMesh - a mesh to store created boundary elements in
12487  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
12488  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
12489  *                                boundary elements will be copied into the targetMesh
12490  *  \param toAddExistingBondary - if true, not only new but also pre-existing
12491  *                                boundary elements will be added into the new group
12492  *  \param aroundElements - if true, elements will be created on boundary of given
12493  *                          elements else, on boundary of the whole mesh.
12494  * \return nb of added boundary elements
12495  */
12496 //================================================================================
12497
12498 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
12499                                        Bnd_Dimension           dimension,
12500                                        SMESH_Group*            group/*=0*/,
12501                                        SMESH_Mesh*             targetMesh/*=0*/,
12502                                        bool                    toCopyElements/*=false*/,
12503                                        bool                    toCopyExistingBoundary/*=false*/,
12504                                        bool                    toAddExistingBondary/*= false*/,
12505                                        bool                    aroundElements/*= false*/)
12506 {
12507   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
12508   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
12509   // hope that all elements are of the same type, do not check them all
12510   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
12511     throw SALOME_Exception(LOCALIZED("wrong element type"));
12512
12513   if ( !targetMesh )
12514     toCopyElements = toCopyExistingBoundary = false;
12515
12516   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
12517   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
12518   int nbAddedBnd = 0;
12519
12520   // editor adding present bnd elements and optionally holding elements to add to the group
12521   SMESH_MeshEditor* presentEditor;
12522   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
12523   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
12524
12525   SMESH_MesherHelper helper( *myMesh );
12526   const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
12527   SMDS_VolumeTool vTool;
12528   TIDSortedElemSet avoidSet;
12529   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
12530   size_t inode;
12531
12532   typedef vector<const SMDS_MeshNode*> TConnectivity;
12533   TConnectivity tgtNodes;
12534   ElemFeatures elemKind( missType );
12535
12536   SMDS_ElemIteratorPtr eIt;
12537   if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
12538   else                  eIt = elemSetIterator( elements );
12539
12540   while (eIt->more())
12541   {
12542     const SMDS_MeshElement* elem = eIt->next();
12543     const int              iQuad = elem->IsQuadratic();
12544     elemKind.SetQuad( iQuad );
12545
12546     // ------------------------------------------------------------------------------------
12547     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
12548     // ------------------------------------------------------------------------------------
12549     vector<const SMDS_MeshElement*> presentBndElems;
12550     vector<TConnectivity>           missingBndElems;
12551     TConnectivity nodes, elemNodes;
12552     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
12553     {
12554       vTool.SetExternalNormal();
12555       const SMDS_MeshElement* otherVol = 0;
12556       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
12557       {
12558         if ( !vTool.IsFreeFace(iface, &otherVol) &&
12559              ( !aroundElements || elements.count( otherVol )))
12560           continue;
12561         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
12562         const size_t nbFaceNodes = vTool.NbFaceNodes (iface);
12563         if ( missType == SMDSAbs_Edge ) // boundary edges
12564         {
12565           nodes.resize( 2+iQuad );
12566           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
12567           {
12568             for ( int j = 0; j < nodes.size(); ++j )
12569               nodes[j] =nn[i+j];
12570             if ( const SMDS_MeshElement* edge =
12571                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
12572               presentBndElems.push_back( edge );
12573             else
12574               missingBndElems.push_back( nodes );
12575           }
12576         }
12577         else // boundary face
12578         {
12579           nodes.clear();
12580           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
12581             nodes.push_back( nn[inode] ); // add corner nodes
12582           if (iQuad)
12583             for ( inode = 1; inode < nbFaceNodes; inode += 2)
12584               nodes.push_back( nn[inode] ); // add medium nodes
12585           int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
12586           if ( iCenter > 0 )
12587             nodes.push_back( vTool.GetNodes()[ iCenter ] );
12588
12589           if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
12590                                                                SMDSAbs_Face, /*noMedium=*/false ))
12591             presentBndElems.push_back( f );
12592           else
12593             missingBndElems.push_back( nodes );
12594
12595           if ( targetMesh != myMesh )
12596           {
12597             // add 1D elements on face boundary to be added to a new mesh
12598             const SMDS_MeshElement* edge;
12599             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
12600             {
12601               if ( iQuad )
12602                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
12603               else
12604                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
12605               if ( edge && avoidSet.insert( edge ).second )
12606                 presentBndElems.push_back( edge );
12607             }
12608           }
12609         }
12610       }
12611     }
12612     else if ( elem->GetType() == SMDSAbs_Face ) // elem is a face ------------------------
12613     {
12614       avoidSet.clear(), avoidSet.insert( elem );
12615       elemNodes.assign( SMDS_MeshElement::iterator( elem->interlacedNodesElemIterator() ),
12616                         SMDS_MeshElement::iterator() );
12617       elemNodes.push_back( elemNodes[0] );
12618       nodes.resize( 2 + iQuad );
12619       const int nbLinks = elem->NbCornerNodes();
12620       for ( int i = 0, iN = 0; i < nbLinks; i++, iN += 1+iQuad )
12621       {
12622         nodes[0] = elemNodes[iN];
12623         nodes[1] = elemNodes[iN+1+iQuad];
12624         if ( SMESH_MeshAlgos::FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
12625           continue; // not free link
12626
12627         if ( iQuad ) nodes[2] = elemNodes[iN+1];
12628         if ( const SMDS_MeshElement* edge =
12629              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
12630           presentBndElems.push_back( edge );
12631         else
12632           missingBndElems.push_back( nodes );
12633       }
12634     }
12635
12636     // ---------------------------------
12637     // 2. Add missing boundary elements
12638     // ---------------------------------
12639     if ( targetMesh != myMesh )
12640       // instead of making a map of nodes in this mesh and targetMesh,
12641       // we create nodes with same IDs.
12642       for ( size_t i = 0; i < missingBndElems.size(); ++i )
12643       {
12644         TConnectivity& srcNodes = missingBndElems[i];
12645         tgtNodes.resize( srcNodes.size() );
12646         for ( inode = 0; inode < srcNodes.size(); ++inode )
12647           tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
12648         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( tgtNodes,
12649                                                                    missType,
12650                                                                    /*noMedium=*/false))
12651           continue;
12652         tgtEditor.AddElement( tgtNodes, elemKind.SetPoly( tgtNodes.size()/(iQuad+1) > 4 ));
12653         ++nbAddedBnd;
12654       }
12655     else
12656       for ( int i = 0; i < missingBndElems.size(); ++i )
12657       {
12658         TConnectivity& nodes = missingBndElems[i];
12659         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
12660                                                                    missType,
12661                                                                    /*noMedium=*/false))
12662           continue;
12663         SMDS_MeshElement* newElem = 
12664           tgtEditor.AddElement( nodes, elemKind.SetPoly( nodes.size()/(iQuad+1) > 4 ));
12665         nbAddedBnd += bool( newElem );
12666
12667         // try to set a new element to a shape
12668         if ( myMesh->HasShapeToMesh() )
12669         {
12670           bool ok = true;
12671           set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
12672           const size_t nbN = nodes.size() / (iQuad+1 );
12673           for ( inode = 0; inode < nbN && ok; ++inode )
12674           {
12675             pair<int, TopAbs_ShapeEnum> i_stype =
12676               helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
12677             if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
12678               mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
12679           }
12680           if ( ok && mediumShapes.size() > 1 )
12681           {
12682             set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
12683             pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
12684             for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
12685             {
12686               if (( ok = ( stype_i->first != stype_i_0.first )))
12687                 ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
12688                                         aMesh->IndexToShape( stype_i_0.second ));
12689             }
12690           }
12691           if ( ok && mediumShapes.begin()->first == missShapeType )
12692             aMesh->SetMeshElementOnShape( newElem, mediumShapes.begin()->second );
12693         }
12694       }
12695
12696     // ----------------------------------
12697     // 3. Copy present boundary elements
12698     // ----------------------------------
12699     if ( toCopyExistingBoundary )
12700       for ( int i = 0 ; i < presentBndElems.size(); ++i )
12701       {
12702         const SMDS_MeshElement* e = presentBndElems[i];
12703         tgtNodes.resize( e->NbNodes() );
12704         for ( inode = 0; inode < nodes.size(); ++inode )
12705           tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
12706         presentEditor->AddElement( tgtNodes, elemKind.Init( e ));
12707       }
12708     else // store present elements to add them to a group
12709       for ( int i = 0 ; i < presentBndElems.size(); ++i )
12710       {
12711         presentEditor->myLastCreatedElems.Append( presentBndElems[i] );
12712       }
12713
12714   } // loop on given elements
12715
12716   // ---------------------------------------------
12717   // 4. Fill group with boundary elements
12718   // ---------------------------------------------
12719   if ( group )
12720   {
12721     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
12722       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
12723         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
12724   }
12725   tgtEditor.myLastCreatedElems.Clear();
12726   tgtEditor2.myLastCreatedElems.Clear();
12727
12728   // -----------------------
12729   // 5. Copy given elements
12730   // -----------------------
12731   if ( toCopyElements && targetMesh != myMesh )
12732   {
12733     if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
12734     else                  eIt = elemSetIterator( elements );
12735     while (eIt->more())
12736     {
12737       const SMDS_MeshElement* elem = eIt->next();
12738       tgtNodes.resize( elem->NbNodes() );
12739       for ( inode = 0; inode < tgtNodes.size(); ++inode )
12740         tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
12741       tgtEditor.AddElement( tgtNodes, elemKind.Init( elem ));
12742
12743       tgtEditor.myLastCreatedElems.Clear();
12744     }
12745   }
12746   return nbAddedBnd;
12747 }
12748
12749 //================================================================================
12750 /*!
12751  * \brief Copy node position and set \a to node on the same geometry
12752  */
12753 //================================================================================
12754
12755 void SMESH_MeshEditor::copyPosition( const SMDS_MeshNode* from,
12756                                      const SMDS_MeshNode* to )
12757 {
12758   if ( !from || !to ) return;
12759
12760   SMDS_PositionPtr pos = from->GetPosition();
12761   if ( !pos || from->getshapeId() < 1 ) return;
12762
12763   switch ( pos->GetTypeOfPosition() )
12764   {
12765   case SMDS_TOP_3DSPACE: break;
12766
12767   case SMDS_TOP_FACE:
12768   {
12769     const SMDS_FacePosition* fPos = static_cast< const SMDS_FacePosition* >( pos );
12770     GetMeshDS()->SetNodeOnFace( to, from->getshapeId(),
12771                                 fPos->GetUParameter(), fPos->GetVParameter() );
12772     break;
12773   }
12774   case SMDS_TOP_EDGE:
12775   {
12776     // WARNING: it is dangerous to set equal nodes on one EDGE!!!!!!!!
12777     const SMDS_EdgePosition* ePos = static_cast< const SMDS_EdgePosition* >( pos );
12778     GetMeshDS()->SetNodeOnEdge( to, from->getshapeId(), ePos->GetUParameter() );
12779     break;
12780   }
12781   case SMDS_TOP_VERTEX:
12782   {
12783     GetMeshDS()->SetNodeOnVertex( to, from->getshapeId() );
12784     break;
12785   }
12786   case SMDS_TOP_UNSPEC:
12787   default:;
12788   }
12789 }