Salome HOME
Update translation files from Crowdin
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 // Copyright (C) 2007-2014  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::CrearLastCreated()
135 {
136   myLastCreatedNodes.Clear();
137   myLastCreatedElems.Clear();
138 }
139
140
141 //=======================================================================
142 /*!
143  * \brief Add element
144  */
145 //=======================================================================
146
147 SMDS_MeshElement*
148 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
149                              const SMDSAbs_ElementType            type,
150                              const bool                           isPoly,
151                              const int                            ID,
152                              const double                         ballDiameter)
153 {
154   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
155   SMDS_MeshElement* e = 0;
156   int nbnode = node.size();
157   SMESHDS_Mesh* mesh = GetMeshDS();
158   switch ( type ) {
159   case SMDSAbs_Face:
160     if ( !isPoly ) {
161       if      (nbnode == 3) {
162         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
163         else           e = mesh->AddFace      (node[0], node[1], node[2] );
164       }
165       else if (nbnode == 4) {
166         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
167         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
168       }
169       else if (nbnode == 6) {
170         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
171                                                node[4], node[5], ID);
172         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
173                                                node[4], node[5] );
174       }
175       else if (nbnode == 7) {
176         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
177                                                node[4], node[5], node[6], ID);
178         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
179                                                node[4], node[5], node[6] );
180       }
181       else if (nbnode == 8) {
182         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
183                                                node[4], node[5], node[6], node[7], ID);
184         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
185                                                node[4], node[5], node[6], node[7] );
186       }
187       else if (nbnode == 9) {
188         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
189                                                node[4], node[5], node[6], node[7], node[8], ID);
190         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
191                                                node[4], node[5], node[6], node[7], node[8] );
192       }
193     } else {
194       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
195       else           e = mesh->AddPolygonalFace      (node    );
196     }
197     break;
198
199   case SMDSAbs_Volume:
200     if ( !isPoly ) {
201       if      (nbnode == 4) {
202         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
203         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
204       }
205       else if (nbnode == 5) {
206         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
207                                                  node[4], ID);
208         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
209                                                  node[4] );
210       }
211       else if (nbnode == 6) {
212         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
213                                                  node[4], node[5], ID);
214         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
215                                                  node[4], node[5] );
216       }
217       else if (nbnode == 8) {
218         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
219                                                  node[4], node[5], node[6], node[7], ID);
220         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
221                                                  node[4], node[5], node[6], node[7] );
222       }
223       else if (nbnode == 10) {
224         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
225                                                  node[4], node[5], node[6], node[7],
226                                                  node[8], node[9], ID);
227         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
228                                                  node[4], node[5], node[6], node[7],
229                                                  node[8], node[9] );
230       }
231       else if (nbnode == 12) {
232         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
233                                                  node[4], node[5], node[6], node[7],
234                                                  node[8], node[9], node[10], node[11], ID);
235         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
236                                                  node[4], node[5], node[6], node[7],
237                                                  node[8], node[9], node[10], node[11] );
238       }
239       else if (nbnode == 13) {
240         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
241                                                  node[4], node[5], node[6], node[7],
242                                                  node[8], node[9], node[10],node[11],
243                                                  node[12],ID);
244         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
245                                                  node[4], node[5], node[6], node[7],
246                                                  node[8], node[9], node[10],node[11],
247                                                  node[12] );
248       }
249       else if (nbnode == 15) {
250         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
251                                                  node[4], node[5], node[6], node[7],
252                                                  node[8], node[9], node[10],node[11],
253                                                  node[12],node[13],node[14],ID);
254         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
255                                                  node[4], node[5], node[6], node[7],
256                                                  node[8], node[9], node[10],node[11],
257                                                  node[12],node[13],node[14] );
258       }
259       else if (nbnode == 20) {
260         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
261                                                  node[4], node[5], node[6], node[7],
262                                                  node[8], node[9], node[10],node[11],
263                                                  node[12],node[13],node[14],node[15],
264                                                  node[16],node[17],node[18],node[19],ID);
265         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
266                                                  node[4], node[5], node[6], node[7],
267                                                  node[8], node[9], node[10],node[11],
268                                                  node[12],node[13],node[14],node[15],
269                                                  node[16],node[17],node[18],node[19] );
270       }
271       else if (nbnode == 27) {
272         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
273                                                  node[4], node[5], node[6], node[7],
274                                                  node[8], node[9], node[10],node[11],
275                                                  node[12],node[13],node[14],node[15],
276                                                  node[16],node[17],node[18],node[19],
277                                                  node[20],node[21],node[22],node[23],
278                                                  node[24],node[25],node[26], ID);
279         else           e = mesh->AddVolume      (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],node[13],node[14],node[15],
283                                                  node[16],node[17],node[18],node[19],
284                                                  node[20],node[21],node[22],node[23],
285                                                  node[24],node[25],node[26] );
286       }
287     }
288     break;
289
290   case SMDSAbs_Edge:
291     if ( nbnode == 2 ) {
292       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
293       else           e = mesh->AddEdge      (node[0], node[1] );
294     }
295     else if ( nbnode == 3 ) {
296       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
297       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
298     }
299     break;
300
301   case SMDSAbs_0DElement:
302     if ( nbnode == 1 ) {
303       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
304       else           e = mesh->Add0DElement      (node[0] );
305     }
306     break;
307
308   case SMDSAbs_Node:
309     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
310     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
311     break;
312
313   case SMDSAbs_Ball:
314     if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], ballDiameter, ID);
315     else           e = mesh->AddBall      (node[0], ballDiameter);
316     break;
317
318   default:;
319   }
320   if ( e ) myLastCreatedElems.Append( e );
321   return e;
322 }
323
324 //=======================================================================
325 /*!
326  * \brief Add element
327  */
328 //=======================================================================
329
330 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
331                                                const SMDSAbs_ElementType type,
332                                                const bool                isPoly,
333                                                const int                 ID)
334 {
335   vector<const SMDS_MeshNode*> nodes;
336   nodes.reserve( nodeIDs.size() );
337   vector<int>::const_iterator id = nodeIDs.begin();
338   while ( id != nodeIDs.end() ) {
339     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
340       nodes.push_back( node );
341     else
342       return 0;
343   }
344   return AddElement( nodes, type, isPoly, ID );
345 }
346
347 //=======================================================================
348 //function : Remove
349 //purpose  : Remove a node or an element.
350 //           Modify a compute state of sub-meshes which become empty
351 //=======================================================================
352
353 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
354                               const bool         isNodes )
355 {
356   myLastCreatedElems.Clear();
357   myLastCreatedNodes.Clear();
358
359   SMESHDS_Mesh* aMesh = GetMeshDS();
360   set< SMESH_subMesh *> smmap;
361
362   int removed = 0;
363   list<int>::const_iterator it = theIDs.begin();
364   for ( ; it != theIDs.end(); it++ ) {
365     const SMDS_MeshElement * elem;
366     if ( isNodes )
367       elem = aMesh->FindNode( *it );
368     else
369       elem = aMesh->FindElement( *it );
370     if ( !elem )
371       continue;
372
373     // Notify VERTEX sub-meshes about modification
374     if ( isNodes ) {
375       const SMDS_MeshNode* node = cast2Node( elem );
376       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
377         if ( int aShapeID = node->getshapeId() )
378           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
379             smmap.insert( sm );
380     }
381     // Find sub-meshes to notify about modification
382     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
383     //     while ( nodeIt->more() ) {
384     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
385     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
386     //       if ( aPosition.get() ) {
387     //         if ( int aShapeID = aPosition->GetShapeId() ) {
388     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
389     //             smmap.insert( sm );
390     //         }
391     //       }
392     //     }
393
394     // Do remove
395     if ( isNodes )
396       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
397     else
398       aMesh->RemoveElement( elem );
399     removed++;
400   }
401
402   // Notify sub-meshes about modification
403   if ( !smmap.empty() ) {
404     set< SMESH_subMesh *>::iterator smIt;
405     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
406       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
407   }
408
409   //   // Check if the whole mesh becomes empty
410   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
411   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
412
413   return removed;
414 }
415
416 //================================================================================
417 /*!
418  * \brief Create 0D elements on all nodes of the given object except those
419  *        nodes on which a 0D element already exists.
420  *  \param elements - Elements on whose nodes to create 0D elements; if empty, 
421  *                    the all mesh is treated
422  *  \param all0DElems - returns all 0D elements found or created on nodes of \a elements
423  */
424 //================================================================================
425
426 void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements,
427                                                    TIDSortedElemSet&       all0DElems )
428 {
429   SMDS_ElemIteratorPtr elemIt;
430   vector< const SMDS_MeshElement* > allNodes;
431   if ( elements.empty() )
432   {
433     allNodes.reserve( GetMeshDS()->NbNodes() );
434     elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node );
435     while ( elemIt->more() )
436       allNodes.push_back( elemIt->next() );
437
438     elemIt = elemSetIterator( allNodes );
439   }
440   else
441   {
442     elemIt = elemSetIterator( elements );
443   }
444
445   while ( elemIt->more() )
446   {
447     const SMDS_MeshElement* e = elemIt->next();
448     SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
449     while ( nodeIt->more() )
450     {
451       const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
452       SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement );
453       if ( it0D->more() )
454         all0DElems.insert( it0D->next() );
455       else {
456         myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n ));
457         all0DElems.insert( myLastCreatedElems.Last() );
458       }
459     }
460   }
461 }
462
463 //=======================================================================
464 //function : FindShape
465 //purpose  : Return an index of the shape theElem is on
466 //           or zero if a shape not found
467 //=======================================================================
468
469 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
470 {
471   myLastCreatedElems.Clear();
472   myLastCreatedNodes.Clear();
473
474   SMESHDS_Mesh * aMesh = GetMeshDS();
475   if ( aMesh->ShapeToMesh().IsNull() )
476     return 0;
477
478   int aShapeID = theElem->getshapeId();
479   if ( aShapeID < 1 )
480     return 0;
481
482   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
483     if ( sm->Contains( theElem ))
484       return aShapeID;
485
486   if ( theElem->GetType() == SMDSAbs_Node ) {
487     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
488   }
489   else {
490     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
491   }
492
493   TopoDS_Shape aShape; // the shape a node of theElem is on
494   if ( theElem->GetType() != SMDSAbs_Node )
495   {
496     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
497     while ( nodeIt->more() ) {
498       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
499       if ((aShapeID = node->getshapeId()) > 0) {
500         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
501           if ( sm->Contains( theElem ))
502             return aShapeID;
503           if ( aShape.IsNull() )
504             aShape = aMesh->IndexToShape( aShapeID );
505         }
506       }
507     }
508   }
509
510   // None of nodes is on a proper shape,
511   // find the shape among ancestors of aShape on which a node is
512   if ( !aShape.IsNull() ) {
513     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
514     for ( ; ancIt.More(); ancIt.Next() ) {
515       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
516       if ( sm && sm->Contains( theElem ))
517         return aMesh->ShapeToIndex( ancIt.Value() );
518     }
519   }
520   else
521   {
522     SMESHDS_SubMeshIteratorPtr smIt = GetMeshDS()->SubMeshes();
523     while ( const SMESHDS_SubMesh* sm = smIt->next() )
524       if ( sm->Contains( theElem ))
525         return sm->GetID();
526   }
527
528   return 0;
529 }
530
531 //=======================================================================
532 //function : IsMedium
533 //purpose  :
534 //=======================================================================
535
536 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
537                                 const SMDSAbs_ElementType typeToCheck)
538 {
539   bool isMedium = false;
540   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
541   while (it->more() && !isMedium ) {
542     const SMDS_MeshElement* elem = it->next();
543     isMedium = elem->IsMediumNode(node);
544   }
545   return isMedium;
546 }
547
548 //=======================================================================
549 //function : shiftNodesQuadTria
550 //purpose  : Shift nodes in the array corresponded to quadratic triangle
551 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
552 //=======================================================================
553
554 static void shiftNodesQuadTria(vector< const SMDS_MeshNode* >& aNodes)
555 {
556   const SMDS_MeshNode* nd1 = aNodes[0];
557   aNodes[0] = aNodes[1];
558   aNodes[1] = aNodes[2];
559   aNodes[2] = nd1;
560   const SMDS_MeshNode* nd2 = aNodes[3];
561   aNodes[3] = aNodes[4];
562   aNodes[4] = aNodes[5];
563   aNodes[5] = nd2;
564 }
565
566 //=======================================================================
567 //function : nbEdgeConnectivity
568 //purpose  : return number of the edges connected with the theNode.
569 //           if theEdges has connections with the other type of the
570 //           elements, return -1
571 //=======================================================================
572
573 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
574 {
575   // SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
576   // int nb=0;
577   // while(elemIt->more()) {
578   //   elemIt->next();
579   //   nb++;
580   // }
581   // return nb;
582   return theNode->NbInverseElements();
583 }
584
585 //=======================================================================
586 //function : getNodesFromTwoTria
587 //purpose  : 
588 //=======================================================================
589
590 static bool getNodesFromTwoTria(const SMDS_MeshElement * theTria1,
591                                 const SMDS_MeshElement * theTria2,
592                                 vector< const SMDS_MeshNode*>& N1,
593                                 vector< const SMDS_MeshNode*>& N2)
594 {
595   N1.assign( theTria1->begin_nodes(), theTria1->end_nodes() );
596   if ( N1.size() < 6 ) return false;
597   N2.assign( theTria2->begin_nodes(), theTria2->end_nodes() );
598   if ( N2.size() < 6 ) return false;
599
600   int sames[3] = {-1,-1,-1};
601   int nbsames = 0;
602   int i, j;
603   for(i=0; i<3; i++) {
604     for(j=0; j<3; j++) {
605       if(N1[i]==N2[j]) {
606         sames[i] = j;
607         nbsames++;
608         break;
609       }
610     }
611   }
612   if(nbsames!=2) return false;
613   if(sames[0]>-1) {
614     shiftNodesQuadTria(N1);
615     if(sames[1]>-1) {
616       shiftNodesQuadTria(N1);
617     }
618   }
619   i = sames[0] + sames[1] + sames[2];
620   for(; i<2; i++) {
621     shiftNodesQuadTria(N2);
622   }
623   // now we receive following N1 and N2 (using numeration as in the image below)
624   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
625   // i.e. first nodes from both arrays form a new diagonal
626   return true;
627 }
628
629 //=======================================================================
630 //function : InverseDiag
631 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
632 //           but having other common link.
633 //           Return False if args are improper
634 //=======================================================================
635
636 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
637                                     const SMDS_MeshElement * theTria2 )
638 {
639   MESSAGE("InverseDiag");
640   myLastCreatedElems.Clear();
641   myLastCreatedNodes.Clear();
642
643   if (!theTria1 || !theTria2)
644     return false;
645
646   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
647   if (!F1) return false;
648   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
649   if (!F2) return false;
650   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
651       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
652
653     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
654     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
655     //    |/ |                                         | \|
656     //  B +--+ 2                                     B +--+ 2
657
658     // put nodes in array and find out indices of the same ones
659     const SMDS_MeshNode* aNodes [6];
660     int sameInd [] = { -1, -1, -1, -1, -1, -1 };
661     int i = 0;
662     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
663     while ( it->more() ) {
664       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
665
666       if ( i > 2 ) // theTria2
667         // find same node of theTria1
668         for ( int j = 0; j < 3; j++ )
669           if ( aNodes[ i ] == aNodes[ j ]) {
670             sameInd[ j ] = i;
671             sameInd[ i ] = j;
672             break;
673           }
674       // next
675       i++;
676       if ( i == 3 ) {
677         if ( it->more() )
678           return false; // theTria1 is not a triangle
679         it = theTria2->nodesIterator();
680       }
681       if ( i == 6 && it->more() )
682         return false; // theTria2 is not a triangle
683     }
684
685     // find indices of 1,2 and of A,B in theTria1
686     int iA = -1, iB = 0, i1 = 0, i2 = 0;
687     for ( i = 0; i < 6; i++ ) {
688       if ( sameInd [ i ] == -1 ) {
689         if ( i < 3 ) i1 = i;
690         else         i2 = i;
691       }
692       else if (i < 3) {
693         if ( iA >= 0) iB = i;
694         else          iA = i;
695       }
696     }
697     // nodes 1 and 2 should not be the same
698     if ( aNodes[ i1 ] == aNodes[ i2 ] )
699       return false;
700
701     // theTria1: A->2
702     aNodes[ iA ] = aNodes[ i2 ];
703     // theTria2: B->1
704     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
705
706     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
707     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
708
709     return true;
710
711   } // end if(F1 && F2)
712
713   // check case of quadratic faces
714   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle &&
715       theTria1->GetEntityType() != SMDSEntity_BiQuad_Triangle)
716     return false;
717   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle&&
718       theTria2->GetEntityType() != SMDSEntity_BiQuad_Triangle)
719     return false;
720
721   //       5
722   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
723   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
724   //    |   / |
725   //  7 +  +  + 6
726   //    | /9  |
727   //    |/    |
728   //  4 +--+--+ 3
729   //       8
730
731   vector< const SMDS_MeshNode* > N1;
732   vector< const SMDS_MeshNode* > N2;
733   if(!getNodesFromTwoTria(theTria1,theTria2,N1,N2))
734     return false;
735   // now we receive following N1 and N2 (using numeration as above image)
736   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
737   // i.e. first nodes from both arrays determ new diagonal
738
739   vector< const SMDS_MeshNode*> N1new( N1.size() );
740   vector< const SMDS_MeshNode*> N2new( N2.size() );
741   N1new.back() = N1.back(); // central node of biquadratic
742   N2new.back() = N2.back();
743   N1new[0] = N1[0];  N2new[0] = N1[0];
744   N1new[1] = N2[0];  N2new[1] = N1[1];
745   N1new[2] = N2[1];  N2new[2] = N2[0];
746   N1new[3] = N1[4];  N2new[3] = N1[3];
747   N1new[4] = N2[3];  N2new[4] = N2[5];
748   N1new[5] = N1[5];  N2new[5] = N1[4];
749   // change nodes in faces
750   GetMeshDS()->ChangeElementNodes( theTria1, &N1new[0], N1new.size() );
751   GetMeshDS()->ChangeElementNodes( theTria2, &N2new[0], N2new.size() );
752
753   // move the central node of biquadratic triangle
754   SMESH_MesherHelper helper( *GetMesh() );
755   for ( int is2nd = 0; is2nd < 2; ++is2nd )
756   {
757     const SMDS_MeshElement*         tria = is2nd ? theTria2 : theTria1;
758     vector< const SMDS_MeshNode*>& nodes = is2nd ? N2new : N1new;
759     if ( nodes.size() < 7 )
760       continue;
761     helper.SetSubShape( tria->getshapeId() );
762     const TopoDS_Face& F = TopoDS::Face( helper.GetSubShape() );
763     gp_Pnt xyz;
764     if ( F.IsNull() )
765     {
766       xyz = ( SMESH_TNodeXYZ( nodes[3] ) +
767               SMESH_TNodeXYZ( nodes[4] ) +
768               SMESH_TNodeXYZ( nodes[5] )) / 3.;
769     }
770     else
771     {
772       bool checkUV;
773       gp_XY uv = ( helper.GetNodeUV( F, nodes[3], nodes[2], &checkUV ) +
774                    helper.GetNodeUV( F, nodes[4], nodes[0], &checkUV ) +
775                    helper.GetNodeUV( F, nodes[5], nodes[1], &checkUV )) / 3.;
776       TopLoc_Location loc;
777       Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc);
778       xyz = S->Value( uv.X(), uv.Y() );
779       xyz.Transform( loc );
780       if ( nodes[6]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE &&  // set UV
781            nodes[6]->getshapeId() > 0 )
782         GetMeshDS()->SetNodeOnFace( nodes[6], nodes[6]->getshapeId(), uv.X(), uv.Y() );
783     }
784     GetMeshDS()->MoveNode( nodes[6], xyz.X(), xyz.Y(), xyz.Z() );
785   }
786   return true;
787 }
788
789 //=======================================================================
790 //function : findTriangles
791 //purpose  : find triangles sharing theNode1-theNode2 link
792 //=======================================================================
793
794 static bool findTriangles(const SMDS_MeshNode *    theNode1,
795                           const SMDS_MeshNode *    theNode2,
796                           const SMDS_MeshElement*& theTria1,
797                           const SMDS_MeshElement*& theTria2)
798 {
799   if ( !theNode1 || !theNode2 ) return false;
800
801   theTria1 = theTria2 = 0;
802
803   set< const SMDS_MeshElement* > emap;
804   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
805   while (it->more()) {
806     const SMDS_MeshElement* elem = it->next();
807     if ( elem->NbCornerNodes() == 3 )
808       emap.insert( elem );
809   }
810   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
811   while (it->more()) {
812     const SMDS_MeshElement* elem = it->next();
813     if ( emap.count( elem )) {
814       if ( !theTria1 )
815       {
816         theTria1 = elem;
817       }
818       else  
819       {
820         theTria2 = elem;
821         // theTria1 must be element with minimum ID
822         if ( theTria2->GetID() < theTria1->GetID() )
823           std::swap( theTria2, theTria1 );
824         return true;
825       }
826     }
827   }
828   return false;
829 }
830
831 //=======================================================================
832 //function : InverseDiag
833 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
834 //           with ones built on the same 4 nodes but having other common link.
835 //           Return false if proper faces not found
836 //=======================================================================
837
838 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
839                                     const SMDS_MeshNode * theNode2)
840 {
841   myLastCreatedElems.Clear();
842   myLastCreatedNodes.Clear();
843
844   MESSAGE( "::InverseDiag()" );
845
846   const SMDS_MeshElement *tr1, *tr2;
847   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
848     return false;
849
850   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
851   if (!F1) return false;
852   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
853   if (!F2) return false;
854   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
855       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
856
857     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
858     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
859     //    |/ |                                    | \|
860     //  B +--+ 2                                B +--+ 2
861
862     // put nodes in array
863     // and find indices of 1,2 and of A in tr1 and of B in tr2
864     int i, iA1 = 0, i1 = 0;
865     const SMDS_MeshNode* aNodes1 [3];
866     SMDS_ElemIteratorPtr it;
867     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
868       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
869       if ( aNodes1[ i ] == theNode1 )
870         iA1 = i; // node A in tr1
871       else if ( aNodes1[ i ] != theNode2 )
872         i1 = i;  // node 1
873     }
874     int iB2 = 0, i2 = 0;
875     const SMDS_MeshNode* aNodes2 [3];
876     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
877       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
878       if ( aNodes2[ i ] == theNode2 )
879         iB2 = i; // node B in tr2
880       else if ( aNodes2[ i ] != theNode1 )
881         i2 = i;  // node 2
882     }
883
884     // nodes 1 and 2 should not be the same
885     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
886       return false;
887
888     // tr1: A->2
889     aNodes1[ iA1 ] = aNodes2[ i2 ];
890     // tr2: B->1
891     aNodes2[ iB2 ] = aNodes1[ i1 ];
892
893     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
894     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
895
896     return true;
897   }
898
899   // check case of quadratic faces
900   return InverseDiag(tr1,tr2);
901 }
902
903 //=======================================================================
904 //function : getQuadrangleNodes
905 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
906 //           fusion of triangles tr1 and tr2 having shared link on
907 //           theNode1 and theNode2
908 //=======================================================================
909
910 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
911                         const SMDS_MeshNode *    theNode1,
912                         const SMDS_MeshNode *    theNode2,
913                         const SMDS_MeshElement * tr1,
914                         const SMDS_MeshElement * tr2 )
915 {
916   if( tr1->NbNodes() != tr2->NbNodes() )
917     return false;
918   // find the 4-th node to insert into tr1
919   const SMDS_MeshNode* n4 = 0;
920   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
921   int i=0;
922   while ( !n4 && i<3 ) {
923     const SMDS_MeshNode * n = cast2Node( it->next() );
924     i++;
925     bool isDiag = ( n == theNode1 || n == theNode2 );
926     if ( !isDiag )
927       n4 = n;
928   }
929   // Make an array of nodes to be in a quadrangle
930   int iNode = 0, iFirstDiag = -1;
931   it = tr1->nodesIterator();
932   i=0;
933   while ( i<3 ) {
934     const SMDS_MeshNode * n = cast2Node( it->next() );
935     i++;
936     bool isDiag = ( n == theNode1 || n == theNode2 );
937     if ( isDiag ) {
938       if ( iFirstDiag < 0 )
939         iFirstDiag = iNode;
940       else if ( iNode - iFirstDiag == 1 )
941         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
942     }
943     else if ( n == n4 ) {
944       return false; // tr1 and tr2 should not have all the same nodes
945     }
946     theQuadNodes[ iNode++ ] = n;
947   }
948   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
949     theQuadNodes[ iNode ] = n4;
950
951   return true;
952 }
953
954 //=======================================================================
955 //function : DeleteDiag
956 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
957 //           with a quadrangle built on the same 4 nodes.
958 //           Return false if proper faces not found
959 //=======================================================================
960
961 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
962                                    const SMDS_MeshNode * theNode2)
963 {
964   myLastCreatedElems.Clear();
965   myLastCreatedNodes.Clear();
966
967   MESSAGE( "::DeleteDiag()" );
968
969   const SMDS_MeshElement *tr1, *tr2;
970   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
971     return false;
972
973   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
974   if (!F1) return false;
975   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
976   if (!F2) return false;
977   SMESHDS_Mesh * aMesh = GetMeshDS();
978
979   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
980       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
981
982     const SMDS_MeshNode* aNodes [ 4 ];
983     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
984       return false;
985
986     const SMDS_MeshElement* newElem = 0;
987     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
988     myLastCreatedElems.Append(newElem);
989     AddToSameGroups( newElem, tr1, aMesh );
990     int aShapeId = tr1->getshapeId();
991     if ( aShapeId )
992       {
993         aMesh->SetMeshElementOnShape( newElem, aShapeId );
994       }
995     aMesh->RemoveElement( tr1 );
996     aMesh->RemoveElement( tr2 );
997
998     return true;
999   }
1000
1001   // check case of quadratic faces
1002   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
1003     return false;
1004   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
1005     return false;
1006
1007   //       5
1008   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
1009   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
1010   //    |   / |
1011   //  7 +  +  + 6
1012   //    | /9  |
1013   //    |/    |
1014   //  4 +--+--+ 3
1015   //       8
1016
1017   vector< const SMDS_MeshNode* > N1;
1018   vector< const SMDS_MeshNode* > N2;
1019   if(!getNodesFromTwoTria(tr1,tr2,N1,N2))
1020     return false;
1021   // now we receive following N1 and N2 (using numeration as above image)
1022   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
1023   // i.e. first nodes from both arrays determ new diagonal
1024
1025   const SMDS_MeshNode* aNodes[8];
1026   aNodes[0] = N1[0];
1027   aNodes[1] = N1[1];
1028   aNodes[2] = N2[0];
1029   aNodes[3] = N2[1];
1030   aNodes[4] = N1[3];
1031   aNodes[5] = N2[5];
1032   aNodes[6] = N2[3];
1033   aNodes[7] = N1[5];
1034
1035   const SMDS_MeshElement* newElem = 0;
1036   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
1037                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
1038   myLastCreatedElems.Append(newElem);
1039   AddToSameGroups( newElem, tr1, aMesh );
1040   int aShapeId = tr1->getshapeId();
1041   if ( aShapeId )
1042     {
1043       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1044     }
1045   aMesh->RemoveElement( tr1 );
1046   aMesh->RemoveElement( tr2 );
1047
1048   // remove middle node (9)
1049   GetMeshDS()->RemoveNode( N1[4] );
1050
1051   return true;
1052 }
1053
1054 //=======================================================================
1055 //function : Reorient
1056 //purpose  : Reverse theElement orientation
1057 //=======================================================================
1058
1059 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
1060 {
1061   MESSAGE("Reorient");
1062   myLastCreatedElems.Clear();
1063   myLastCreatedNodes.Clear();
1064
1065   if (!theElem)
1066     return false;
1067   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
1068   if ( !it || !it->more() )
1069     return false;
1070
1071   const SMDSAbs_ElementType type = theElem->GetType();
1072   if ( type < SMDSAbs_Edge || type > SMDSAbs_Volume )
1073     return false;
1074
1075   const SMDSAbs_EntityType geomType = theElem->GetEntityType();
1076   if ( geomType == SMDSEntity_Polyhedra ) // polyhedron
1077   {
1078     const SMDS_VtkVolume* aPolyedre =
1079       dynamic_cast<const SMDS_VtkVolume*>( theElem );
1080     if (!aPolyedre) {
1081       MESSAGE("Warning: bad volumic element");
1082       return false;
1083     }
1084     const int nbFaces = aPolyedre->NbFaces();
1085     vector<const SMDS_MeshNode *> poly_nodes;
1086     vector<int> quantities (nbFaces);
1087
1088     // reverse each face of the polyedre
1089     for (int iface = 1; iface <= nbFaces; iface++) {
1090       int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1091       quantities[iface - 1] = nbFaceNodes;
1092
1093       for (inode = nbFaceNodes; inode >= 1; inode--) {
1094         const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1095         poly_nodes.push_back(curNode);
1096       }
1097     }
1098     return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1099   }
1100   else // other elements
1101   {
1102     vector<const SMDS_MeshNode*> nodes( theElem->begin_nodes(), theElem->end_nodes() );
1103     const std::vector<int>& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType );
1104     if ( interlace.empty() )
1105     {
1106       std::reverse( nodes.begin(), nodes.end() ); // polygon
1107     }
1108     else if ( interlace.size() > 1 )
1109     {
1110       SMDS_MeshCell::applyInterlace( interlace, nodes );
1111     }
1112     return GetMeshDS()->ChangeElementNodes( theElem, &nodes[0], nodes.size() );
1113   }
1114   return false;
1115 }
1116
1117 //================================================================================
1118 /*!
1119  * \brief Reorient faces.
1120  * \param theFaces - the faces to reorient. If empty the whole mesh is meant
1121  * \param theDirection - desired direction of normal of \a theFace
1122  * \param theFace - one of \a theFaces that sould be oriented according to
1123  *        \a theDirection and whose orientation defines orientation of other faces
1124  * \return number of reoriented faces.
1125  */
1126 //================================================================================
1127
1128 int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
1129                                   const gp_Dir&            theDirection,
1130                                   const SMDS_MeshElement * theFace)
1131 {
1132   int nbReori = 0;
1133   if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori;
1134
1135   if ( theFaces.empty() )
1136   {
1137     SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true);
1138     while ( fIt->more() )
1139       theFaces.insert( theFaces.end(), fIt->next() );
1140   }
1141
1142   // orient theFace according to theDirection
1143   gp_XYZ normal;
1144   SMESH_MeshAlgos::FaceNormal( theFace, normal, /*normalized=*/false );
1145   if ( normal * theDirection.XYZ() < 0 )
1146     nbReori += Reorient( theFace );
1147
1148   // Orient other faces
1149
1150   set< const SMDS_MeshElement* > startFaces, visitedFaces;
1151   TIDSortedElemSet avoidSet;
1152   set< SMESH_TLink > checkedLinks;
1153   pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
1154
1155   if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
1156     theFaces.erase( theFace );
1157   startFaces.insert( theFace );
1158
1159   int nodeInd1, nodeInd2;
1160   const SMDS_MeshElement*           otherFace;
1161   vector< const SMDS_MeshElement* > facesNearLink;
1162   vector< std::pair< int, int > >   nodeIndsOfFace;
1163
1164   set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
1165   while ( !startFaces.empty() )
1166   {
1167     startFace = startFaces.begin();
1168     theFace = *startFace;
1169     startFaces.erase( startFace );
1170     if ( !visitedFaces.insert( theFace ).second )
1171       continue;
1172
1173     avoidSet.clear();
1174     avoidSet.insert(theFace);
1175
1176     NLink link( theFace->GetNode( 0 ), (SMDS_MeshNode *) 0 );
1177
1178     const int nbNodes = theFace->NbCornerNodes();
1179     for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
1180     {
1181       link.second = theFace->GetNode(( i+1 ) % nbNodes );
1182       linkIt_isNew = checkedLinks.insert( link );
1183       if ( !linkIt_isNew.second )
1184       {
1185         // link has already been checked and won't be encountered more
1186         // if the group (theFaces) is manifold
1187         //checkedLinks.erase( linkIt_isNew.first );
1188       }
1189       else
1190       {
1191         facesNearLink.clear();
1192         nodeIndsOfFace.clear();
1193         while (( otherFace = SMESH_MeshAlgos::FindFaceInSet( link.first, link.second,
1194                                                              theFaces, avoidSet,
1195                                                              &nodeInd1, &nodeInd2 )))
1196           if ( otherFace != theFace)
1197           {
1198             facesNearLink.push_back( otherFace );
1199             nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 ));
1200             avoidSet.insert( otherFace );
1201           }
1202         if ( facesNearLink.size() > 1 )
1203         {
1204           // NON-MANIFOLD mesh shell !
1205           // select a face most co-directed with theFace,
1206           // other faces won't be visited this time
1207           gp_XYZ NF, NOF;
1208           SMESH_MeshAlgos::FaceNormal( theFace, NF, /*normalized=*/false );
1209           double proj, maxProj = -1;
1210           for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
1211             SMESH_MeshAlgos::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
1212             if (( proj = Abs( NF * NOF )) > maxProj ) {
1213               maxProj = proj;
1214               otherFace = facesNearLink[i];
1215               nodeInd1  = nodeIndsOfFace[i].first;
1216               nodeInd2  = nodeIndsOfFace[i].second;
1217             }
1218           }
1219           // not to visit rejected faces
1220           for ( size_t i = 0; i < facesNearLink.size(); ++i )
1221             if ( facesNearLink[i] != otherFace && theFaces.size() > 1 )
1222               visitedFaces.insert( facesNearLink[i] );
1223         }
1224         else if ( facesNearLink.size() == 1 )
1225         {
1226           otherFace = facesNearLink[0];
1227           nodeInd1  = nodeIndsOfFace.back().first;
1228           nodeInd2  = nodeIndsOfFace.back().second;
1229         }
1230         if ( otherFace && otherFace != theFace)
1231         {
1232           // link must be reverse in otherFace if orientation ot otherFace
1233           // is same as that of theFace
1234           if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
1235           {
1236             nbReori += Reorient( otherFace );
1237           }
1238           startFaces.insert( otherFace );
1239         }
1240       }
1241       std::swap( link.first, link.second ); // reverse the link
1242     }
1243   }
1244   return nbReori;
1245 }
1246
1247 //================================================================================
1248 /*!
1249  * \brief Reorient faces basing on orientation of adjacent volumes.
1250  * \param theFaces - faces to reorient. If empty, all mesh faces are treated.
1251  * \param theVolumes - reference volumes.
1252  * \param theOutsideNormal - to orient faces to have their normal
1253  *        pointing either \a outside or \a inside the adjacent volumes.
1254  * \return number of reoriented faces.
1255  */
1256 //================================================================================
1257
1258 int SMESH_MeshEditor::Reorient2DBy3D (TIDSortedElemSet & theFaces,
1259                                       TIDSortedElemSet & theVolumes,
1260                                       const bool         theOutsideNormal)
1261 {
1262   int nbReori = 0;
1263
1264   SMDS_ElemIteratorPtr faceIt;
1265   if ( theFaces.empty() )
1266     faceIt = GetMeshDS()->elementsIterator( SMDSAbs_Face );
1267   else
1268     faceIt = elemSetIterator( theFaces );
1269
1270   vector< const SMDS_MeshNode* > faceNodes;
1271   TIDSortedElemSet checkedVolumes;
1272   set< const SMDS_MeshNode* > faceNodesSet;
1273   SMDS_VolumeTool volumeTool;
1274
1275   while ( faceIt->more() ) // loop on given faces
1276   {
1277     const SMDS_MeshElement* face = faceIt->next();
1278     if ( face->GetType() != SMDSAbs_Face )
1279       continue;
1280
1281     const int nbCornersNodes = face->NbCornerNodes();
1282     faceNodes.assign( face->begin_nodes(), face->end_nodes() );
1283
1284     checkedVolumes.clear();
1285     SMDS_ElemIteratorPtr vIt = faceNodes[ 0 ]->GetInverseElementIterator( SMDSAbs_Volume );
1286     while ( vIt->more() )
1287     {
1288       const SMDS_MeshElement* volume = vIt->next();
1289
1290       if ( !checkedVolumes.insert( volume ).second )
1291         continue;
1292       if ( !theVolumes.empty() && !theVolumes.count( volume ))
1293         continue;
1294
1295       // is volume adjacent?
1296       bool allNodesCommon = true;
1297       for ( int iN = 1; iN < nbCornersNodes && allNodesCommon; ++iN )
1298         allNodesCommon = ( volume->GetNodeIndex( faceNodes[ iN ]) > -1 );
1299       if ( !allNodesCommon )
1300         continue;
1301
1302       // get nodes of a corresponding volume facet
1303       faceNodesSet.clear();
1304       faceNodesSet.insert( faceNodes.begin(), faceNodes.end() );
1305       volumeTool.Set( volume );
1306       int facetID = volumeTool.GetFaceIndex( faceNodesSet );
1307       if ( facetID < 0 ) continue;
1308       volumeTool.SetExternalNormal();
1309       const SMDS_MeshNode** facetNodes = volumeTool.GetFaceNodes( facetID );
1310
1311       // compare order of faceNodes and facetNodes
1312       const int iQ = 1 + ( nbCornersNodes < faceNodes.size() );
1313       int iNN[2];
1314       for ( int i = 0; i < 2; ++i )
1315       {
1316         const SMDS_MeshNode* n = facetNodes[ i*iQ ];
1317         for ( int iN = 0; iN < nbCornersNodes; ++iN )
1318           if ( faceNodes[ iN ] == n )
1319           {
1320             iNN[ i ] = iN;
1321             break;
1322           }
1323       }
1324       bool isOutside = Abs( iNN[0]-iNN[1] ) == 1 ? iNN[0] < iNN[1] : iNN[0] > iNN[1];
1325       if ( isOutside != theOutsideNormal )
1326         nbReori += Reorient( face );
1327     }
1328   }  // loop on given faces
1329
1330   return nbReori;
1331 }
1332
1333 //=======================================================================
1334 //function : getBadRate
1335 //purpose  :
1336 //=======================================================================
1337
1338 static double getBadRate (const SMDS_MeshElement*               theElem,
1339                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1340 {
1341   SMESH::Controls::TSequenceOfXYZ P;
1342   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1343     return 1e100;
1344   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1345   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1346 }
1347
1348 //=======================================================================
1349 //function : QuadToTri
1350 //purpose  : Cut quadrangles into triangles.
1351 //           theCrit is used to select a diagonal to cut
1352 //=======================================================================
1353
1354 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1355                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1356 {
1357   myLastCreatedElems.Clear();
1358   myLastCreatedNodes.Clear();
1359
1360   if ( !theCrit.get() )
1361     return false;
1362
1363   SMESHDS_Mesh * aMesh = GetMeshDS();
1364
1365   Handle(Geom_Surface) surface;
1366   SMESH_MesherHelper   helper( *GetMesh() );
1367
1368   TIDSortedElemSet::iterator itElem;
1369   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
1370   {
1371     const SMDS_MeshElement* elem = *itElem;
1372     if ( !elem || elem->GetType() != SMDSAbs_Face )
1373       continue;
1374     if ( elem->NbCornerNodes() != 4 )
1375       continue;
1376
1377     // retrieve element nodes
1378     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1379
1380     // compare two sets of possible triangles
1381     double aBadRate1, aBadRate2; // to what extent a set is bad
1382     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1383     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1384     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1385
1386     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1387     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1388     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1389
1390     const int aShapeId = FindShape( elem );
1391     const SMDS_MeshElement* newElem1 = 0;
1392     const SMDS_MeshElement* newElem2 = 0;
1393
1394     if ( !elem->IsQuadratic() ) // split liner quadrangle
1395     {
1396       // for MaxElementLength2D functor we return minimum diagonal for splitting,
1397       // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1398       if ( aBadRate1 <= aBadRate2 ) {
1399         // tr1 + tr2 is better
1400         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1401         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1402       }
1403       else {
1404         // tr3 + tr4 is better
1405         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1406         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1407       }
1408     }
1409     else // split quadratic quadrangle
1410     {
1411       helper.SetIsQuadratic( true );
1412       helper.SetIsBiQuadratic( aNodes.size() == 9 );
1413
1414       helper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem ));
1415       if ( aNodes.size() == 9 )
1416       {
1417         helper.SetIsBiQuadratic( true );
1418         if ( aBadRate1 <= aBadRate2 )
1419           helper.AddTLinkNode( aNodes[0], aNodes[2], aNodes[8] );
1420         else
1421           helper.AddTLinkNode( aNodes[1], aNodes[3], aNodes[8] );
1422       }
1423       // create a new element
1424       if ( aBadRate1 <= aBadRate2 ) {
1425         newElem1 = helper.AddFace( aNodes[2], aNodes[3], aNodes[0] );
1426         newElem2 = helper.AddFace( aNodes[2], aNodes[0], aNodes[1] );
1427       }
1428       else {
1429         newElem1 = helper.AddFace( aNodes[3], aNodes[0], aNodes[1] );
1430         newElem2 = helper.AddFace( aNodes[3], aNodes[1], aNodes[2] );
1431       }
1432     } // quadratic case
1433
1434     // care of a new element
1435
1436     myLastCreatedElems.Append(newElem1);
1437     myLastCreatedElems.Append(newElem2);
1438     AddToSameGroups( newElem1, elem, aMesh );
1439     AddToSameGroups( newElem2, elem, aMesh );
1440
1441     // put a new triangle on the same shape
1442     if ( aShapeId )
1443       aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1444     aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1445
1446     aMesh->RemoveElement( elem );
1447   }
1448   return true;
1449 }
1450
1451 //=======================================================================
1452 /*!
1453  * \brief Split each of given quadrangles into 4 triangles.
1454  * \param theElems - The faces to be splitted. If empty all faces are split.
1455  */
1456 //=======================================================================
1457
1458 void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
1459 {
1460   myLastCreatedElems.Clear();
1461   myLastCreatedNodes.Clear();
1462
1463   SMESH_MesherHelper helper( *GetMesh() );
1464   helper.SetElementsOnShape( true );
1465
1466   SMDS_ElemIteratorPtr faceIt;
1467   if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face);
1468   else                    faceIt = elemSetIterator( theElems );
1469
1470   bool   checkUV;
1471   gp_XY  uv [9]; uv[8] = gp_XY(0,0);
1472   gp_XYZ xyz[9];
1473   vector< const SMDS_MeshNode* > nodes;
1474   SMESHDS_SubMesh*               subMeshDS;
1475   TopoDS_Face                    F;
1476   Handle(Geom_Surface)           surface;
1477   TopLoc_Location                loc;
1478
1479   while ( faceIt->more() )
1480   {
1481     const SMDS_MeshElement* quad = faceIt->next();
1482     if ( !quad || quad->NbCornerNodes() != 4 )
1483       continue;
1484
1485     // get a surface the quad is on
1486
1487     if ( quad->getshapeId() < 1 )
1488     {
1489       F.Nullify();
1490       helper.SetSubShape( 0 );
1491       subMeshDS = 0;
1492     }
1493     else if ( quad->getshapeId() != helper.GetSubShapeID() )
1494     {
1495       helper.SetSubShape( quad->getshapeId() );
1496       if ( !helper.GetSubShape().IsNull() &&
1497            helper.GetSubShape().ShapeType() == TopAbs_FACE )
1498       {
1499         F = TopoDS::Face( helper.GetSubShape() );
1500         surface = BRep_Tool::Surface( F, loc );
1501         subMeshDS = GetMeshDS()->MeshElements( quad->getshapeId() );
1502       }
1503       else
1504       {
1505         helper.SetSubShape( 0 );
1506         subMeshDS = 0;
1507       }
1508     }
1509
1510     // create a central node
1511
1512     const SMDS_MeshNode* nCentral;
1513     nodes.assign( quad->begin_nodes(), quad->end_nodes() );
1514
1515     if ( nodes.size() == 9 )
1516     {
1517       nCentral = nodes.back();
1518     }
1519     else
1520     {
1521       size_t iN = 0;
1522       if ( F.IsNull() )
1523       {
1524         for ( ; iN < nodes.size(); ++iN )
1525           xyz[ iN ] = SMESH_TNodeXYZ( nodes[ iN ] );
1526
1527         for ( ; iN < 8; ++iN ) // mid-side points of a linear qudrangle
1528           xyz[ iN ] = 0.5 * ( xyz[ iN - 4 ] + xyz[( iN - 3 )%4 ] );
1529
1530         xyz[ 8 ] = helper.calcTFI( 0.5, 0.5,
1531                                    xyz[0], xyz[1], xyz[2], xyz[3],
1532                                    xyz[4], xyz[5], xyz[6], xyz[7] );
1533       }
1534       else
1535       {
1536         for ( ; iN < nodes.size(); ++iN )
1537           uv[ iN ] = helper.GetNodeUV( F, nodes[iN], nodes[(iN+2)%4], &checkUV );
1538
1539         for ( ; iN < 8; ++iN ) // UV of mid-side points of a linear qudrangle
1540           uv[ iN ] = helper.GetMiddleUV( surface, uv[ iN - 4 ], uv[( iN - 3 )%4 ] );
1541
1542         uv[ 8 ] = helper.calcTFI( 0.5, 0.5,
1543                                   uv[0], uv[1], uv[2], uv[3],
1544                                   uv[4], uv[5], uv[6], uv[7] );
1545
1546         gp_Pnt p = surface->Value( uv[8].X(), uv[8].Y() ).Transformed( loc );
1547         xyz[ 8 ] = p.XYZ();
1548       }
1549
1550       nCentral = helper.AddNode( xyz[8].X(), xyz[8].Y(), xyz[8].Z(), /*id=*/0,
1551                                  uv[8].X(), uv[8].Y() );
1552       myLastCreatedNodes.Append( nCentral );
1553     }
1554
1555     // create 4 triangles
1556
1557     GetMeshDS()->RemoveFreeElement( quad, subMeshDS, /*fromGroups=*/false );
1558     
1559     helper.SetIsQuadratic  ( nodes.size() > 4 );
1560     helper.SetIsBiQuadratic( nodes.size() == 9 );
1561     if ( helper.GetIsQuadratic() )
1562       helper.AddTLinks( static_cast< const SMDS_MeshFace*>( quad ));
1563
1564     for ( int i = 0; i < 4; ++i )
1565     {
1566       SMDS_MeshElement* tria = helper.AddFace( nodes[ i ],
1567                                                nodes[(i+1)%4],
1568                                                nCentral );
1569       ReplaceElemInGroups( tria, quad, GetMeshDS() );
1570       myLastCreatedElems.Append( tria );
1571     }
1572   }
1573 }
1574
1575 //=======================================================================
1576 //function : BestSplit
1577 //purpose  : Find better diagonal for cutting.
1578 //=======================================================================
1579
1580 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1581                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1582 {
1583   myLastCreatedElems.Clear();
1584   myLastCreatedNodes.Clear();
1585
1586   if (!theCrit.get())
1587     return -1;
1588
1589   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1590     return -1;
1591
1592   if( theQuad->NbNodes()==4 ||
1593       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1594
1595     // retrieve element nodes
1596     const SMDS_MeshNode* aNodes [4];
1597     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1598     int i = 0;
1599     //while (itN->more())
1600     while (i<4) {
1601       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1602     }
1603     // compare two sets of possible triangles
1604     double aBadRate1, aBadRate2; // to what extent a set is bad
1605     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1606     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1607     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1608
1609     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1610     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1611     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1612     // for MaxElementLength2D functor we return minimum diagonal for splitting,
1613     // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1614     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1615       return 1; // diagonal 1-3
1616
1617     return 2; // diagonal 2-4
1618   }
1619   return -1;
1620 }
1621
1622 namespace
1623 {
1624   // Methods of splitting volumes into tetra
1625
1626   const int theHexTo5_1[5*4+1] =
1627     {
1628       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1629     };
1630   const int theHexTo5_2[5*4+1] =
1631     {
1632       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1633     };
1634   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1635
1636   const int theHexTo6_1[6*4+1] =
1637     {
1638       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
1639     };
1640   const int theHexTo6_2[6*4+1] =
1641     {
1642       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
1643     };
1644   const int theHexTo6_3[6*4+1] =
1645     {
1646       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
1647     };
1648   const int theHexTo6_4[6*4+1] =
1649     {
1650       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
1651     };
1652   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1653
1654   const int thePyraTo2_1[2*4+1] =
1655     {
1656       0, 1, 2, 4,    0, 2, 3, 4,   -1
1657     };
1658   const int thePyraTo2_2[2*4+1] =
1659     {
1660       1, 2, 3, 4,    1, 3, 0, 4,   -1
1661     };
1662   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1663
1664   const int thePentaTo3_1[3*4+1] =
1665     {
1666       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1667     };
1668   const int thePentaTo3_2[3*4+1] =
1669     {
1670       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1671     };
1672   const int thePentaTo3_3[3*4+1] =
1673     {
1674       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1675     };
1676   const int thePentaTo3_4[3*4+1] =
1677     {
1678       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1679     };
1680   const int thePentaTo3_5[3*4+1] =
1681     {
1682       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1683     };
1684   const int thePentaTo3_6[3*4+1] =
1685     {
1686       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1687     };
1688   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1689                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1690
1691   // Methods of splitting hexahedron into prisms
1692
1693   const int theHexTo4Prisms_BT[6*4+1] = // bottom-top
1694     {
1695       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
1696     };
1697   const int theHexTo4Prisms_LR[6*4+1] = // left-right
1698     {
1699       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
1700     };
1701   const int theHexTo4Prisms_FB[6*4+1] = // front-back
1702     {
1703       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
1704     };
1705
1706   const int theHexTo2Prisms_BT_1[6*2+1] =
1707     {
1708       0, 1, 3, 4, 5, 7,    1, 2, 3, 5, 6, 7,   -1
1709     };
1710   const int theHexTo2Prisms_BT_2[6*2+1] =
1711     {
1712       0, 1, 2, 4, 5, 6,    0, 2, 3, 4, 6, 7,   -1
1713     };
1714   const int* theHexTo2Prisms_BT[2] = { theHexTo2Prisms_BT_1, theHexTo2Prisms_BT_2 };
1715
1716   const int theHexTo2Prisms_LR_1[6*2+1] =
1717     {
1718       1, 0, 4, 2, 3, 7,    1, 4, 5, 2, 7, 6,   -1
1719     };
1720   const int theHexTo2Prisms_LR_2[6*2+1] =
1721     {
1722       1, 0, 4, 2, 3, 7,    1, 4, 5, 2, 7, 6,   -1
1723     };
1724   const int* theHexTo2Prisms_LR[2] = { theHexTo2Prisms_LR_1, theHexTo2Prisms_LR_2 };
1725
1726   const int theHexTo2Prisms_FB_1[6*2+1] =
1727     {
1728       0, 3, 4, 1, 2, 5,    3, 7, 4, 2, 6, 5,   -1
1729     };
1730   const int theHexTo2Prisms_FB_2[6*2+1] =
1731     {
1732       0, 3, 7, 1, 2, 7,    0, 7, 4, 1, 6, 5,   -1
1733     };
1734   const int* theHexTo2Prisms_FB[2] = { theHexTo2Prisms_FB_1, theHexTo2Prisms_FB_2 };
1735
1736
1737   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1738   {
1739     int _n1, _n2, _n3;
1740     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1741     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1742     bool hasAdjacentVol( const SMDS_MeshElement*    elem,
1743                          const SMDSAbs_GeometryType geom = SMDSGeom_TETRA) const;
1744   };
1745   struct TSplitMethod
1746   {
1747     int        _nbSplits;
1748     int        _nbCorners;
1749     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1750     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1751     bool       _ownConn;      //!< to delete _connectivity in destructor
1752     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1753
1754     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1755       : _nbSplits(nbTet), _nbCorners(4), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1756     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1757     bool hasFacet( const TTriangleFacet& facet ) const
1758     {
1759       if ( _nbCorners == 4 )
1760       {
1761         const int* tetConn = _connectivity;
1762         for ( ; tetConn[0] >= 0; tetConn += 4 )
1763           if (( facet.contains( tetConn[0] ) +
1764                 facet.contains( tetConn[1] ) +
1765                 facet.contains( tetConn[2] ) +
1766                 facet.contains( tetConn[3] )) == 3 )
1767             return true;
1768       }
1769       else // prism, _nbCorners == 6
1770       {
1771         const int* prismConn = _connectivity;
1772         for ( ; prismConn[0] >= 0; prismConn += 6 )
1773         {
1774           if (( facet.contains( prismConn[0] ) &&
1775                 facet.contains( prismConn[1] ) &&
1776                 facet.contains( prismConn[2] ))
1777               ||
1778               ( facet.contains( prismConn[3] ) &&
1779                 facet.contains( prismConn[4] ) &&
1780                 facet.contains( prismConn[5] )))
1781             return true;
1782         }
1783       }
1784       return false;
1785     }
1786   };
1787
1788   //=======================================================================
1789   /*!
1790    * \brief return TSplitMethod for the given element to split into tetrahedra
1791    */
1792   //=======================================================================
1793
1794   TSplitMethod getTetraSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1795   {
1796     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1797
1798     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1799     // an edge and a face barycenter; tertaherdons are based on triangles and
1800     // a volume barycenter
1801     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1802
1803     // Find out how adjacent volumes are split
1804
1805     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1806     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1807     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1808     {
1809       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1810       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1811       if ( nbNodes < 4 ) continue;
1812
1813       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1814       const int* nInd = vol.GetFaceNodesIndices( iF );
1815       if ( nbNodes == 4 )
1816       {
1817         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1818         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1819         if      ( t012.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t012 );
1820         else if ( t123.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t123 );
1821       }
1822       else
1823       {
1824         int iCom = 0; // common node of triangle faces to split into
1825         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1826         {
1827           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1828                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1829                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1830           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1831                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1832                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1833           if ( t012.hasAdjacentVol( vol.Element() ) && t023.hasAdjacentVol( vol.Element() ))
1834           {
1835             triaSplits.push_back( t012 );
1836             triaSplits.push_back( t023 );
1837             break;
1838           }
1839         }
1840       }
1841       if ( !triaSplits.empty() )
1842         hasAdjacentSplits = true;
1843     }
1844
1845     // Among variants of split method select one compliant with adjacent volumes
1846
1847     TSplitMethod method;
1848     if ( !vol.Element()->IsPoly() && !is24TetMode )
1849     {
1850       int nbVariants = 2, nbTet = 0;
1851       const int** connVariants = 0;
1852       switch ( vol.Element()->GetEntityType() )
1853       {
1854       case SMDSEntity_Hexa:
1855       case SMDSEntity_Quad_Hexa:
1856       case SMDSEntity_TriQuad_Hexa:
1857         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1858           connVariants = theHexTo5, nbTet = 5;
1859         else
1860           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1861         break;
1862       case SMDSEntity_Pyramid:
1863       case SMDSEntity_Quad_Pyramid:
1864         connVariants = thePyraTo2;  nbTet = 2;
1865         break;
1866       case SMDSEntity_Penta:
1867       case SMDSEntity_Quad_Penta:
1868         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1869         break;
1870       default:
1871         nbVariants = 0;
1872       }
1873       for ( int variant = 0; variant < nbVariants && method._nbSplits == 0; ++variant )
1874       {
1875         // check method compliancy with adjacent tetras,
1876         // all found splits must be among facets of tetras described by this method
1877         method = TSplitMethod( nbTet, connVariants[variant] );
1878         if ( hasAdjacentSplits && method._nbSplits > 0 )
1879         {
1880           bool facetCreated = true;
1881           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1882           {
1883             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1884             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1885               facetCreated = method.hasFacet( *facet );
1886           }
1887           if ( !facetCreated )
1888             method = TSplitMethod(0); // incompatible method
1889         }
1890       }
1891     }
1892     if ( method._nbSplits < 1 )
1893     {
1894       // No standard method is applicable, use a generic solution:
1895       // each facet of a volume is split into triangles and
1896       // each of triangles and a volume barycenter form a tetrahedron.
1897
1898       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1899
1900       int* connectivity = new int[ maxTetConnSize + 1 ];
1901       method._connectivity = connectivity;
1902       method._ownConn = true;
1903       method._baryNode = !isHex27; // to create central node or not
1904
1905       int connSize = 0;
1906       int baryCenInd = vol.NbNodes() - int( isHex27 );
1907       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1908       {
1909         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1910         const int*   nInd = vol.GetFaceNodesIndices( iF );
1911         // find common node of triangle facets of tetra to create
1912         int iCommon = 0; // index in linear numeration
1913         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1914         if ( !triaSplits.empty() )
1915         {
1916           // by found facets
1917           const TTriangleFacet* facet = &triaSplits.front();
1918           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1919             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1920                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1921               break;
1922         }
1923         else if ( nbNodes > 3 && !is24TetMode )
1924         {
1925           // find the best method of splitting into triangles by aspect ratio
1926           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1927           map< double, int > badness2iCommon;
1928           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1929           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1930           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1931           {
1932             double badness = 0;
1933             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1934             {
1935               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1936                                       nodes[ iQ*((iLast-1)%nbNodes)],
1937                                       nodes[ iQ*((iLast  )%nbNodes)]);
1938               badness += getBadRate( &tria, aspectRatio );
1939             }
1940             badness2iCommon.insert( make_pair( badness, iCommon ));
1941           }
1942           // use iCommon with lowest badness
1943           iCommon = badness2iCommon.begin()->second;
1944         }
1945         if ( iCommon >= nbNodes )
1946           iCommon = 0; // something wrong
1947
1948         // fill connectivity of tetrahedra based on a current face
1949         int nbTet = nbNodes - 2;
1950         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1951         {
1952           int faceBaryCenInd;
1953           if ( isHex27 )
1954           {
1955             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
1956             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
1957           }
1958           else
1959           {
1960             method._faceBaryNode[ iF ] = 0;
1961             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1962           }
1963           nbTet = nbNodes;
1964           for ( int i = 0; i < nbTet; ++i )
1965           {
1966             int i1 = i, i2 = (i+1) % nbNodes;
1967             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1968             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1969             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1970             connectivity[ connSize++ ] = faceBaryCenInd;
1971             connectivity[ connSize++ ] = baryCenInd;
1972           }
1973         }
1974         else
1975         {
1976           for ( int i = 0; i < nbTet; ++i )
1977           {
1978             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1979             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1980             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1981             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1982             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1983             connectivity[ connSize++ ] = baryCenInd;
1984           }
1985         }
1986         method._nbSplits += nbTet;
1987
1988       } // loop on volume faces
1989
1990       connectivity[ connSize++ ] = -1;
1991
1992     } // end of generic solution
1993
1994     return method;
1995   }
1996   //=======================================================================
1997   /*!
1998    * \brief return TSplitMethod to split haxhedron into prisms
1999    */
2000   //=======================================================================
2001
2002   TSplitMethod getPrismSplitMethod( SMDS_VolumeTool& vol,
2003                                     const int        methodFlags,
2004                                     const int        facetToSplit)
2005   {
2006     // order of facets in HEX according to SMDS_VolumeTool::Hexa_F :
2007     // B, T, L, B, R, F
2008     const int iF = ( facetToSplit < 2 ) ? 0 : 1 + ( facetToSplit-2 ) % 2; // [0,1,2]
2009
2010     if ( methodFlags == SMESH_MeshEditor::HEXA_TO_4_PRISMS )
2011     {
2012       static TSplitMethod to4methods[4]; // order BT, LR, FB
2013       if ( to4methods[iF]._nbSplits == 0 )
2014       {
2015         switch ( iF ) {
2016         case 0:
2017           to4methods[iF]._connectivity = theHexTo4Prisms_BT;
2018           to4methods[iF]._faceBaryNode[ 0 ] = 0;
2019           to4methods[iF]._faceBaryNode[ 1 ] = 0;
2020           break;
2021         case 1:
2022           to4methods[iF]._connectivity = theHexTo4Prisms_LR;
2023           to4methods[iF]._faceBaryNode[ 2 ] = 0;
2024           to4methods[iF]._faceBaryNode[ 4 ] = 0;
2025           break;
2026         case 2:
2027           to4methods[iF]._connectivity = theHexTo4Prisms_FB;
2028           to4methods[iF]._faceBaryNode[ 3 ] = 0;
2029           to4methods[iF]._faceBaryNode[ 5 ] = 0;
2030           break;
2031         default: return to4methods[3];
2032         }
2033         to4methods[iF]._nbSplits  = 4;
2034         to4methods[iF]._nbCorners = 6;
2035       }
2036       return to4methods[iF];
2037     }
2038     // else if ( methodFlags == HEXA_TO_2_PRISMS )
2039
2040     TSplitMethod method;
2041
2042     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
2043
2044     const int nbVariants = 2, nbSplits = 2;
2045     const int** connVariants = 0;
2046     switch ( iF ) {
2047     case 0: connVariants = theHexTo2Prisms_BT; break;
2048     case 1: connVariants = theHexTo2Prisms_LR; break;
2049     case 2: connVariants = theHexTo2Prisms_FB; break;
2050     default: return method;
2051     }
2052
2053     // look for prisms adjacent via facetToSplit and an opposite one
2054     for ( int is2nd = 0; is2nd < 2; ++is2nd )
2055     {
2056       int iFacet = is2nd ? vol.GetOppFaceIndexOfHex( facetToSplit ) : facetToSplit;
2057       int nbNodes = vol.NbFaceNodes( iFacet ) / iQ;
2058       if ( nbNodes != 4 ) return method;
2059
2060       const int* nInd = vol.GetFaceNodesIndices( iFacet );
2061       TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
2062       TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
2063       TTriangleFacet* t;
2064       if      ( t012.hasAdjacentVol( vol.Element(), SMDSGeom_PENTA ))
2065         t = &t012;
2066       else if ( t123.hasAdjacentVol( vol.Element(), SMDSGeom_PENTA ))
2067         t = &t123;
2068       else
2069         continue;
2070
2071       // there are adjacent prism
2072       for ( int variant = 0; variant < nbVariants; ++variant )
2073       {
2074         // check method compliancy with adjacent prisms,
2075         // the found prism facets must be among facets of prisms described by current method
2076         method._nbSplits     = nbSplits;
2077         method._nbCorners    = 6;
2078         method._connectivity = connVariants[ variant ];
2079         if ( method.hasFacet( *t ))
2080           return method;
2081       }
2082     }
2083
2084     // No adjacent prisms. Select a variant with a best aspect ratio.
2085
2086     double badness[2] = { 0, 0 };
2087     static SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
2088     const SMDS_MeshNode** nodes = vol.GetNodes();
2089     for ( int variant = 0; variant < nbVariants; ++variant )
2090       for ( int is2nd = 0; is2nd < 2; ++is2nd )
2091       {
2092         int iFacet = is2nd ? vol.GetOppFaceIndexOfHex( facetToSplit ) : facetToSplit;
2093         const int*             nInd = vol.GetFaceNodesIndices( iFacet );
2094
2095         method._connectivity = connVariants[ variant ];
2096         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
2097         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
2098         TTriangleFacet* t = ( method.hasFacet( t012 )) ? & t012 : & t123;
2099
2100         SMDS_FaceOfNodes tria ( nodes[ t->_n1 ],
2101                                 nodes[ t->_n2 ],
2102                                 nodes[ t->_n3 ] );
2103         badness[ variant ] += getBadRate( &tria, aspectRatio );
2104       }
2105     const int iBetter = ( badness[1] < badness[0] && badness[0]-badness[1] > 0.1 * badness[0] );
2106
2107     method._nbSplits     = nbSplits;
2108     method._nbCorners    = 6;
2109     method._connectivity = connVariants[ iBetter ];
2110
2111     return method;
2112   }
2113
2114   //================================================================================
2115   /*!
2116    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
2117    */
2118   //================================================================================
2119
2120   bool TTriangleFacet::hasAdjacentVol( const SMDS_MeshElement*    elem,
2121                                        const SMDSAbs_GeometryType geom ) const
2122   {
2123     // find the tetrahedron including the three nodes of facet
2124     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
2125     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
2126     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
2127     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
2128     while ( volIt1->more() )
2129     {
2130       const SMDS_MeshElement* v = volIt1->next();
2131       if ( v->GetGeomType() != geom )
2132         continue;
2133       const int lastCornerInd = v->NbCornerNodes() - 1;
2134       if ( v->IsQuadratic() && v->GetNodeIndex( n1 ) > lastCornerInd )
2135         continue; // medium node not allowed
2136       const int ind2 = v->GetNodeIndex( n2 );
2137       if ( ind2 < 0 || lastCornerInd < ind2 )
2138         continue;
2139       const int ind3 = v->GetNodeIndex( n3 );
2140       if ( ind3 < 0 || lastCornerInd < ind3 )
2141         continue;
2142       return true;
2143     }
2144     return false;
2145   }
2146
2147   //=======================================================================
2148   /*!
2149    * \brief A key of a face of volume
2150    */
2151   //=======================================================================
2152
2153   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
2154   {
2155     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
2156     {
2157       TIDSortedNodeSet sortedNodes;
2158       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
2159       int nbNodes = vol.NbFaceNodes( iF );
2160       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
2161       for ( int i = 0; i < nbNodes; i += iQ )
2162         sortedNodes.insert( fNodes[i] );
2163       TIDSortedNodeSet::iterator n = sortedNodes.begin();
2164       first.first   = (*(n++))->GetID();
2165       first.second  = (*(n++))->GetID();
2166       second.first  = (*(n++))->GetID();
2167       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
2168     }
2169   };
2170 } // namespace
2171
2172 //=======================================================================
2173 //function : SplitVolumes
2174 //purpose  : Split volume elements into tetrahedra or prisms.
2175 //           If facet ID < 0, element is split into tetrahedra,
2176 //           else a hexahedron is split into prisms so that the given facet is
2177 //           split into triangles
2178 //=======================================================================
2179
2180 void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems,
2181                                      const int            theMethodFlags)
2182 {
2183   // std-like iterator on coordinates of nodes of mesh element
2184   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
2185   NXyzIterator xyzEnd;
2186
2187   SMDS_VolumeTool    volTool;
2188   SMESH_MesherHelper helper( *GetMesh()), fHelper(*GetMesh());
2189   fHelper.ToFixNodeParameters( true );
2190
2191   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
2192   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
2193
2194   SMESH_SequenceOfElemPtr newNodes, newElems;
2195
2196   // map face of volume to it's baricenrtic node
2197   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
2198   double bc[3];
2199
2200   TFacetOfElem::const_iterator elem2facet = theElems.begin();
2201   for ( ; elem2facet != theElems.end(); ++elem2facet )
2202   {
2203     const SMDS_MeshElement* elem = elem2facet->first;
2204     const int       facetToSplit = elem2facet->second;
2205     if ( elem->GetType() != SMDSAbs_Volume )
2206       continue;
2207     const SMDSAbs_EntityType geomType = elem->GetEntityType();
2208     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
2209       continue;
2210
2211     if ( !volTool.Set( elem, /*ignoreCentralNodes=*/false )) continue; // strange...
2212
2213     TSplitMethod splitMethod = ( facetToSplit < 0  ?
2214                                  getTetraSplitMethod( volTool, theMethodFlags ) :
2215                                  getPrismSplitMethod( volTool, theMethodFlags, facetToSplit ));
2216     if ( splitMethod._nbSplits < 1 ) continue;
2217
2218     // find submesh to add new tetras to
2219     if ( !subMesh || !subMesh->Contains( elem ))
2220     {
2221       int shapeID = FindShape( elem );
2222       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
2223       subMesh = GetMeshDS()->MeshElements( shapeID );
2224     }
2225     int iQ;
2226     if ( elem->IsQuadratic() )
2227     {
2228       iQ = 2;
2229       // add quadratic links to the helper
2230       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
2231       {
2232         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
2233         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
2234         for ( int iN = 0; iN < nbN; iN += iQ )
2235           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
2236       }
2237       helper.SetIsQuadratic( true );
2238     }
2239     else
2240     {
2241       iQ = 1;
2242       helper.SetIsQuadratic( false );
2243     }
2244     vector<const SMDS_MeshNode*> nodes( volTool.GetNodes(),
2245                                         volTool.GetNodes() + elem->NbNodes() );
2246     helper.SetElementsOnShape( true );
2247     if ( splitMethod._baryNode )
2248     {
2249       // make a node at barycenter
2250       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
2251       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
2252       nodes.push_back( gcNode );
2253       newNodes.Append( gcNode );
2254     }
2255     if ( !splitMethod._faceBaryNode.empty() )
2256     {
2257       // make or find baricentric nodes of faces
2258       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
2259       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
2260       {
2261         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
2262           volFace2BaryNode.insert
2263           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
2264         if ( !f_n->second )
2265         {
2266           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
2267           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
2268         }
2269         nodes.push_back( iF_n->second = f_n->second );
2270       }
2271     }
2272
2273     // make new volumes
2274     vector<const SMDS_MeshElement* > splitVols( splitMethod._nbSplits ); // splits of a volume
2275     const int* volConn = splitMethod._connectivity;
2276     if ( splitMethod._nbCorners == 4 ) // tetra
2277       for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners )
2278         newElems.Append( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ],
2279                                                             nodes[ volConn[1] ],
2280                                                             nodes[ volConn[2] ],
2281                                                             nodes[ volConn[3] ]));
2282     else // prisms
2283       for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners )
2284         newElems.Append( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ],
2285                                                             nodes[ volConn[1] ],
2286                                                             nodes[ volConn[2] ],
2287                                                             nodes[ volConn[3] ],
2288                                                             nodes[ volConn[4] ],
2289                                                             nodes[ volConn[5] ]));
2290
2291     ReplaceElemInGroups( elem, splitVols, GetMeshDS() );
2292
2293     // Split faces on sides of the split volume
2294
2295     const SMDS_MeshNode** volNodes = volTool.GetNodes();
2296     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
2297     {
2298       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
2299       if ( nbNodes < 4 ) continue;
2300
2301       // find an existing face
2302       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
2303                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
2304       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
2305                                                                        /*noMedium=*/false))
2306       {
2307         // make triangles
2308         helper.SetElementsOnShape( false );
2309         vector< const SMDS_MeshElement* > triangles;
2310
2311         // find submesh to add new triangles in
2312         if ( !fSubMesh || !fSubMesh->Contains( face ))
2313         {
2314           int shapeID = FindShape( face );
2315           fSubMesh = GetMeshDS()->MeshElements( shapeID );
2316         }
2317         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
2318         if ( iF_n != splitMethod._faceBaryNode.end() )
2319         {
2320           const SMDS_MeshNode *baryNode = iF_n->second;
2321           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
2322           {
2323             const SMDS_MeshNode* n1 = fNodes[iN];
2324             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
2325             const SMDS_MeshNode *n3 = baryNode;
2326             if ( !volTool.IsFaceExternal( iF ))
2327               swap( n2, n3 );
2328             triangles.push_back( helper.AddFace( n1,n2,n3 ));
2329           }
2330           if ( fSubMesh ) // update position of the bary node on geometry
2331           {
2332             if ( subMesh )
2333               subMesh->RemoveNode( baryNode, false );
2334             GetMeshDS()->SetNodeOnFace( baryNode, fSubMesh->GetID() );
2335             const TopoDS_Shape& s = GetMeshDS()->IndexToShape( fSubMesh->GetID() );
2336             if ( !s.IsNull() && s.ShapeType() == TopAbs_FACE )
2337             {
2338               fHelper.SetSubShape( s );
2339               gp_XY uv( 1e100, 1e100 );
2340               double distXYZ[4];
2341               if ( !fHelper.CheckNodeUV( TopoDS::Face( s ), baryNode,
2342                                         uv, /*tol=*/1e-7, /*force=*/true, distXYZ ) &&
2343                    uv.X() < 1e100 )
2344               {
2345                 // node is too far from the surface
2346                 GetMeshDS()->MoveNode( baryNode, distXYZ[1], distXYZ[2], distXYZ[3] );
2347                 const_cast<SMDS_MeshNode*>( baryNode )->SetPosition
2348                   ( SMDS_PositionPtr( new SMDS_FacePosition( uv.X(), uv.Y() )));
2349               }
2350             }
2351           }
2352         }
2353         else
2354         {
2355           // among possible triangles create ones discribed by split method
2356           const int* nInd = volTool.GetFaceNodesIndices( iF );
2357           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
2358           int iCom = 0; // common node of triangle faces to split into
2359           list< TTriangleFacet > facets;
2360           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
2361           {
2362             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
2363                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
2364                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
2365             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
2366                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
2367                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
2368             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
2369             {
2370               facets.push_back( t012 );
2371               facets.push_back( t023 );
2372               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
2373                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
2374                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
2375                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
2376               break;
2377             }
2378           }
2379           list< TTriangleFacet >::iterator facet = facets.begin();
2380           if ( facet == facets.end() )
2381             break;
2382           for ( ; facet != facets.end(); ++facet )
2383           {
2384             if ( !volTool.IsFaceExternal( iF ))
2385               swap( facet->_n2, facet->_n3 );
2386             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
2387                                                  volNodes[ facet->_n2 ],
2388                                                  volNodes[ facet->_n3 ]));
2389           }
2390         }
2391         for ( int i = 0; i < triangles.size(); ++i )
2392         {
2393           if ( !triangles[i] ) continue;
2394           if ( fSubMesh )
2395             fSubMesh->AddElement( triangles[i]);
2396           newElems.Append( triangles[i] );
2397         }
2398         ReplaceElemInGroups( face, triangles, GetMeshDS() );
2399         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
2400
2401       } // while a face based on facet nodes exists
2402     } // loop on volume faces to split them into triangles
2403
2404     GetMeshDS()->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false );
2405
2406     if ( geomType == SMDSEntity_TriQuad_Hexa )
2407     {
2408       // remove medium nodes that could become free
2409       for ( int i = 20; i < volTool.NbNodes(); ++i )
2410         if ( volNodes[i]->NbInverseElements() == 0 )
2411           GetMeshDS()->RemoveNode( volNodes[i] );
2412     }
2413   } // loop on volumes to split
2414   
2415   myLastCreatedNodes = newNodes;
2416   myLastCreatedElems = newElems;
2417 }
2418
2419 //=======================================================================
2420 //function : GetHexaFacetsToSplit
2421 //purpose  : For hexahedra that will be split into prisms, finds facets to
2422 //           split into triangles. Only hexahedra adjacent to the one closest
2423 //           to theFacetNormal.Location() are returned.
2424 //param [in,out] theHexas - the hexahedra
2425 //param [in]     theFacetNormal - facet normal
2426 //param [out]    theFacets - the hexahedra and found facet IDs
2427 //=======================================================================
2428
2429 void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas,
2430                                              const gp_Ax1&     theFacetNormal,
2431                                              TFacetOfElem &    theFacets)
2432 {
2433   #define THIS_METHOD "SMESH_MeshEditor::GetHexaFacetsToSplit(): "
2434
2435   // Find a hexa closest to the location of theFacetNormal
2436
2437   const SMDS_MeshElement* startHex;
2438   {
2439     // get SMDS_ElemIteratorPtr on theHexas
2440     typedef const SMDS_MeshElement*                                      TValue;
2441     typedef TIDSortedElemSet::iterator                                   TSetIterator;
2442     typedef SMDS::SimpleAccessor<TValue,TSetIterator>                    TAccesor;
2443     typedef SMDS_MeshElement::GeomFilter                                 TFilter;
2444     typedef SMDS_SetIterator < TValue, TSetIterator, TAccesor, TFilter > TElemSetIter;
2445     SMDS_ElemIteratorPtr elemIt = SMDS_ElemIteratorPtr
2446       ( new TElemSetIter( theHexas.begin(),
2447                           theHexas.end(),
2448                           SMDS_MeshElement::GeomFilter( SMDSGeom_HEXA )));
2449
2450     SMESH_ElementSearcher* searcher =
2451       SMESH_MeshAlgos::GetElementSearcher( *myMesh->GetMeshDS(), elemIt );
2452
2453     startHex = searcher->FindClosestTo( theFacetNormal.Location(), SMDSAbs_Volume );
2454
2455     delete searcher;
2456
2457     if ( !startHex )
2458       throw SALOME_Exception( THIS_METHOD "startHex not found");
2459   }
2460
2461   // Select a facet of startHex by theFacetNormal
2462
2463   SMDS_VolumeTool vTool( startHex );
2464   double norm[3], dot, maxDot = 0;
2465   int facetID = -1;
2466   for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
2467     if ( vTool.GetFaceNormal( iF, norm[0], norm[1], norm[2] ))
2468     {
2469       dot = Abs( theFacetNormal.Direction().Dot( gp_Dir( norm[0], norm[1], norm[2] )));
2470       if ( dot > maxDot )
2471       {
2472         facetID = iF;
2473         maxDot = dot;
2474       }
2475     }
2476   if ( facetID < 0 )
2477     throw SALOME_Exception( THIS_METHOD "facet of startHex not found");
2478
2479   // Fill theFacets starting from facetID of startHex
2480
2481   // facets used for seach of volumes adjacent to already treated ones
2482   typedef pair< TFacetOfElem::iterator, int > TElemFacets;
2483   typedef map< TVolumeFaceKey, TElemFacets  > TFacetMap;
2484   TFacetMap facetsToCheck;
2485
2486   set<const SMDS_MeshNode*> facetNodes;
2487   const SMDS_MeshElement*   curHex;
2488
2489   const bool allHex = ( theHexas.size() == myMesh->NbHexas() );
2490
2491   while ( startHex )
2492   {
2493     // move in two directions from startHex via facetID
2494     for ( int is2nd = 0; is2nd < 2; ++is2nd )
2495     {
2496       curHex       = startHex;
2497       int curFacet = facetID;
2498       if ( is2nd ) // do not treat startHex twice
2499       {
2500         vTool.Set( curHex );
2501         if ( vTool.IsFreeFace( curFacet, &curHex ))
2502         {
2503           curHex = 0;
2504         }
2505         else
2506         {
2507           vTool.GetFaceNodes( curFacet, facetNodes );
2508           vTool.Set( curHex );
2509           curFacet = vTool.GetFaceIndex( facetNodes );
2510         }
2511       }
2512       while ( curHex )
2513       {
2514         // store a facet to split
2515         if ( curHex->GetGeomType() != SMDSGeom_HEXA )
2516         {
2517           theFacets.insert( make_pair( curHex, -1 ));
2518           break;
2519         }
2520         if ( !allHex && !theHexas.count( curHex ))
2521           break;
2522
2523         pair< TFacetOfElem::iterator, bool > facetIt2isNew =
2524           theFacets.insert( make_pair( curHex, curFacet ));
2525         if ( !facetIt2isNew.second )
2526           break;
2527
2528         // remember not-to-split facets in facetsToCheck
2529         int oppFacet = vTool.GetOppFaceIndexOfHex( curFacet );
2530         for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
2531         {
2532           if ( iF == curFacet && iF == oppFacet )
2533             continue;
2534           TVolumeFaceKey facetKey ( vTool, iF );
2535           TElemFacets    elemFacet( facetIt2isNew.first, iF );
2536           pair< TFacetMap::iterator, bool > it2isnew =
2537             facetsToCheck.insert( make_pair( facetKey, elemFacet ));
2538           if ( !it2isnew.second )
2539             facetsToCheck.erase( it2isnew.first ); // adjacent hex already checked
2540         }
2541         // pass to a volume adjacent via oppFacet
2542         if ( vTool.IsFreeFace( oppFacet, &curHex ))
2543         {
2544           curHex = 0;
2545         }
2546         else
2547         {
2548           // get a new curFacet
2549           vTool.GetFaceNodes( oppFacet, facetNodes );
2550           vTool.Set( curHex );
2551           curFacet = vTool.GetFaceIndex( facetNodes, /*hint=*/curFacet );
2552         }
2553       }
2554     } // move in two directions from startHex via facetID
2555
2556     // Find a new startHex by facetsToCheck
2557
2558     startHex = 0;
2559     facetID  = -1;
2560     TFacetMap::iterator fIt = facetsToCheck.begin();
2561     while ( !startHex && fIt != facetsToCheck.end() )
2562     {
2563       const TElemFacets&  elemFacets = fIt->second;
2564       const SMDS_MeshElement*    hex = elemFacets.first->first;
2565       int                 splitFacet = elemFacets.first->second;
2566       int               lateralFacet = elemFacets.second;
2567       facetsToCheck.erase( fIt );
2568       fIt = facetsToCheck.begin();
2569
2570       vTool.Set( hex );
2571       if ( vTool.IsFreeFace( lateralFacet, &curHex ) || 
2572            curHex->GetGeomType() != SMDSGeom_HEXA )
2573         continue;
2574       if ( !allHex && !theHexas.count( curHex ))
2575         continue;
2576
2577       startHex = curHex;
2578
2579       // find a facet of startHex to split 
2580
2581       set<const SMDS_MeshNode*> lateralNodes;
2582       vTool.GetFaceNodes( lateralFacet, lateralNodes );
2583       vTool.GetFaceNodes( splitFacet,   facetNodes );
2584       int oppLateralFacet = vTool.GetOppFaceIndexOfHex( lateralFacet );
2585       vTool.Set( startHex );
2586       lateralFacet = vTool.GetFaceIndex( lateralNodes, oppLateralFacet );
2587
2588       // look for a facet of startHex having common nodes with facetNodes
2589       // but not lateralFacet
2590       for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
2591       {
2592         if ( iF == lateralFacet )
2593           continue;
2594         int nbCommonNodes = 0;
2595         const SMDS_MeshNode** nn = vTool.GetFaceNodes( iF );
2596         for ( int iN = 0, nbN = vTool.NbFaceNodes( iF ); iN < nbN; ++iN )
2597           nbCommonNodes += facetNodes.count( nn[ iN ]);
2598
2599         if ( nbCommonNodes >= 2 )
2600         {
2601           facetID = iF;
2602           break;
2603         }
2604       }
2605       if ( facetID < 0 )
2606         throw SALOME_Exception( THIS_METHOD "facet of a new startHex not found");
2607     }
2608   } //   while ( startHex )
2609 }
2610
2611 //=======================================================================
2612 //function : AddToSameGroups
2613 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
2614 //=======================================================================
2615
2616 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
2617                                         const SMDS_MeshElement* elemInGroups,
2618                                         SMESHDS_Mesh *          aMesh)
2619 {
2620   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2621   if (!groups.empty()) {
2622     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2623     for ( ; grIt != groups.end(); grIt++ ) {
2624       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2625       if ( group && group->Contains( elemInGroups ))
2626         group->SMDSGroup().Add( elemToAdd );
2627     }
2628   }
2629 }
2630
2631
2632 //=======================================================================
2633 //function : RemoveElemFromGroups
2634 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
2635 //=======================================================================
2636 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
2637                                              SMESHDS_Mesh *          aMesh)
2638 {
2639   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2640   if (!groups.empty())
2641   {
2642     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
2643     for (; GrIt != groups.end(); GrIt++)
2644     {
2645       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
2646       if (!grp || grp->IsEmpty()) continue;
2647       grp->SMDSGroup().Remove(removeelem);
2648     }
2649   }
2650 }
2651
2652 //================================================================================
2653 /*!
2654  * \brief Replace elemToRm by elemToAdd in the all groups
2655  */
2656 //================================================================================
2657
2658 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
2659                                             const SMDS_MeshElement* elemToAdd,
2660                                             SMESHDS_Mesh *          aMesh)
2661 {
2662   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2663   if (!groups.empty()) {
2664     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2665     for ( ; grIt != groups.end(); grIt++ ) {
2666       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2667       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
2668         group->SMDSGroup().Add( elemToAdd );
2669     }
2670   }
2671 }
2672
2673 //================================================================================
2674 /*!
2675  * \brief Replace elemToRm by elemToAdd in the all groups
2676  */
2677 //================================================================================
2678
2679 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
2680                                             const vector<const SMDS_MeshElement*>& elemToAdd,
2681                                             SMESHDS_Mesh *                         aMesh)
2682 {
2683   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2684   if (!groups.empty())
2685   {
2686     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2687     for ( ; grIt != groups.end(); grIt++ ) {
2688       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2689       if ( group && group->SMDSGroup().Remove( elemToRm ) )
2690         for ( int i = 0; i < elemToAdd.size(); ++i )
2691           group->SMDSGroup().Add( elemToAdd[ i ] );
2692     }
2693   }
2694 }
2695
2696 //=======================================================================
2697 //function : QuadToTri
2698 //purpose  : Cut quadrangles into triangles.
2699 //           theCrit is used to select a diagonal to cut
2700 //=======================================================================
2701
2702 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
2703                                   const bool         the13Diag)
2704 {
2705   myLastCreatedElems.Clear();
2706   myLastCreatedNodes.Clear();
2707
2708   MESSAGE( "::QuadToTri()" );
2709
2710   SMESHDS_Mesh * aMesh = GetMeshDS();
2711
2712   Handle(Geom_Surface) surface;
2713   SMESH_MesherHelper   helper( *GetMesh() );
2714
2715   TIDSortedElemSet::iterator itElem;
2716   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2717     const SMDS_MeshElement* elem = *itElem;
2718     if ( !elem || elem->GetType() != SMDSAbs_Face )
2719       continue;
2720     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
2721     if(!isquad) continue;
2722
2723     if(elem->NbNodes()==4) {
2724       // retrieve element nodes
2725       const SMDS_MeshNode* aNodes [4];
2726       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2727       int i = 0;
2728       while ( itN->more() )
2729         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2730
2731       int aShapeId = FindShape( elem );
2732       const SMDS_MeshElement* newElem1 = 0;
2733       const SMDS_MeshElement* newElem2 = 0;
2734       if ( the13Diag ) {
2735         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
2736         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
2737       }
2738       else {
2739         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
2740         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
2741       }
2742       myLastCreatedElems.Append(newElem1);
2743       myLastCreatedElems.Append(newElem2);
2744       // put a new triangle on the same shape and add to the same groups
2745       if ( aShapeId )
2746         {
2747           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2748           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2749         }
2750       AddToSameGroups( newElem1, elem, aMesh );
2751       AddToSameGroups( newElem2, elem, aMesh );
2752       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
2753       aMesh->RemoveElement( elem );
2754     }
2755
2756     // Quadratic quadrangle
2757
2758     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
2759
2760       // get surface elem is on
2761       int aShapeId = FindShape( elem );
2762       if ( aShapeId != helper.GetSubShapeID() ) {
2763         surface.Nullify();
2764         TopoDS_Shape shape;
2765         if ( aShapeId > 0 )
2766           shape = aMesh->IndexToShape( aShapeId );
2767         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
2768           TopoDS_Face face = TopoDS::Face( shape );
2769           surface = BRep_Tool::Surface( face );
2770           if ( !surface.IsNull() )
2771             helper.SetSubShape( shape );
2772         }
2773       }
2774
2775       const SMDS_MeshNode* aNodes [8];
2776       const SMDS_MeshNode* inFaceNode = 0;
2777       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2778       int i = 0;
2779       while ( itN->more() ) {
2780         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2781         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
2782              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
2783         {
2784           inFaceNode = aNodes[ i-1 ];
2785         }
2786       }
2787
2788       // find middle point for (0,1,2,3)
2789       // and create a node in this point;
2790       gp_XYZ p( 0,0,0 );
2791       if ( surface.IsNull() ) {
2792         for(i=0; i<4; i++)
2793           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
2794         p /= 4;
2795       }
2796       else {
2797         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
2798         gp_XY uv( 0,0 );
2799         for(i=0; i<4; i++)
2800           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
2801         uv /= 4.;
2802         p = surface->Value( uv.X(), uv.Y() ).XYZ();
2803       }
2804       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
2805       myLastCreatedNodes.Append(newN);
2806
2807       // create a new element
2808       const SMDS_MeshElement* newElem1 = 0;
2809       const SMDS_MeshElement* newElem2 = 0;
2810       if ( the13Diag ) {
2811         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
2812                                   aNodes[6], aNodes[7], newN );
2813         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
2814                                   newN,      aNodes[4], aNodes[5] );
2815       }
2816       else {
2817         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
2818                                   aNodes[7], aNodes[4], newN );
2819         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
2820                                   newN,      aNodes[5], aNodes[6] );
2821       }
2822       myLastCreatedElems.Append(newElem1);
2823       myLastCreatedElems.Append(newElem2);
2824       // put a new triangle on the same shape and add to the same groups
2825       if ( aShapeId )
2826         {
2827           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2828           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2829         }
2830       AddToSameGroups( newElem1, elem, aMesh );
2831       AddToSameGroups( newElem2, elem, aMesh );
2832       aMesh->RemoveElement( elem );
2833     }
2834   }
2835
2836   return true;
2837 }
2838
2839 //=======================================================================
2840 //function : getAngle
2841 //purpose  :
2842 //=======================================================================
2843
2844 double getAngle(const SMDS_MeshElement * tr1,
2845                 const SMDS_MeshElement * tr2,
2846                 const SMDS_MeshNode *    n1,
2847                 const SMDS_MeshNode *    n2)
2848 {
2849   double angle = 2. * M_PI; // bad angle
2850
2851   // get normals
2852   SMESH::Controls::TSequenceOfXYZ P1, P2;
2853   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2854        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2855     return angle;
2856   gp_Vec N1,N2;
2857   if(!tr1->IsQuadratic())
2858     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2859   else
2860     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2861   if ( N1.SquareMagnitude() <= gp::Resolution() )
2862     return angle;
2863   if(!tr2->IsQuadratic())
2864     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2865   else
2866     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2867   if ( N2.SquareMagnitude() <= gp::Resolution() )
2868     return angle;
2869
2870   // find the first diagonal node n1 in the triangles:
2871   // take in account a diagonal link orientation
2872   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2873   for ( int t = 0; t < 2; t++ ) {
2874     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2875     int i = 0, iDiag = -1;
2876     while ( it->more()) {
2877       const SMDS_MeshElement *n = it->next();
2878       if ( n == n1 || n == n2 ) {
2879         if ( iDiag < 0)
2880           iDiag = i;
2881         else {
2882           if ( i - iDiag == 1 )
2883             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2884           else
2885             nFirst[ t ] = n;
2886           break;
2887         }
2888       }
2889       i++;
2890     }
2891   }
2892   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2893     N2.Reverse();
2894
2895   angle = N1.Angle( N2 );
2896   //SCRUTE( angle );
2897   return angle;
2898 }
2899
2900 // =================================================
2901 // class generating a unique ID for a pair of nodes
2902 // and able to return nodes by that ID
2903 // =================================================
2904 class LinkID_Gen {
2905 public:
2906
2907   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2908     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2909   {}
2910
2911   long GetLinkID (const SMDS_MeshNode * n1,
2912                   const SMDS_MeshNode * n2) const
2913   {
2914     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2915   }
2916
2917   bool GetNodes (const long             theLinkID,
2918                  const SMDS_MeshNode* & theNode1,
2919                  const SMDS_MeshNode* & theNode2) const
2920   {
2921     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2922     if ( !theNode1 ) return false;
2923     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2924     if ( !theNode2 ) return false;
2925     return true;
2926   }
2927
2928 private:
2929   LinkID_Gen();
2930   const SMESHDS_Mesh* myMesh;
2931   long                myMaxID;
2932 };
2933
2934
2935 //=======================================================================
2936 //function : TriToQuad
2937 //purpose  : Fuse neighbour triangles into quadrangles.
2938 //           theCrit is used to select a neighbour to fuse with.
2939 //           theMaxAngle is a max angle between element normals at which
2940 //           fusion is still performed.
2941 //=======================================================================
2942
2943 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2944                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2945                                   const double                         theMaxAngle)
2946 {
2947   myLastCreatedElems.Clear();
2948   myLastCreatedNodes.Clear();
2949
2950   MESSAGE( "::TriToQuad()" );
2951
2952   if ( !theCrit.get() )
2953     return false;
2954
2955   SMESHDS_Mesh * aMesh = GetMeshDS();
2956
2957   // Prepare data for algo: build
2958   // 1. map of elements with their linkIDs
2959   // 2. map of linkIDs with their elements
2960
2961   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2962   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2963   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2964   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2965
2966   TIDSortedElemSet::iterator itElem;
2967   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
2968   {
2969     const SMDS_MeshElement* elem = *itElem;
2970     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2971     bool IsTria = ( elem->NbCornerNodes()==3 );
2972     if (!IsTria) continue;
2973
2974     // retrieve element nodes
2975     const SMDS_MeshNode* aNodes [4];
2976     SMDS_NodeIteratorPtr itN = elem->nodeIterator();
2977     int i = 0;
2978     while ( i < 3 )
2979       aNodes[ i++ ] = itN->next();
2980     aNodes[ 3 ] = aNodes[ 0 ];
2981
2982     // fill maps
2983     for ( i = 0; i < 3; i++ ) {
2984       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2985       // check if elements sharing a link can be fused
2986       itLE = mapLi_listEl.find( link );
2987       if ( itLE != mapLi_listEl.end() ) {
2988         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2989           continue;
2990         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2991         //if ( FindShape( elem ) != FindShape( elem2 ))
2992         //  continue; // do not fuse triangles laying on different shapes
2993         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2994           continue; // avoid making badly shaped quads
2995         (*itLE).second.push_back( elem );
2996       }
2997       else {
2998         mapLi_listEl[ link ].push_back( elem );
2999       }
3000       mapEl_setLi [ elem ].insert( link );
3001     }
3002   }
3003   // Clean the maps from the links shared by a sole element, ie
3004   // links to which only one element is bound in mapLi_listEl
3005
3006   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
3007     int nbElems = (*itLE).second.size();
3008     if ( nbElems < 2  ) {
3009       const SMDS_MeshElement* elem = (*itLE).second.front();
3010       SMESH_TLink link = (*itLE).first;
3011       mapEl_setLi[ elem ].erase( link );
3012       if ( mapEl_setLi[ elem ].empty() )
3013         mapEl_setLi.erase( elem );
3014     }
3015   }
3016
3017   // Algo: fuse triangles into quadrangles
3018
3019   while ( ! mapEl_setLi.empty() ) {
3020     // Look for the start element:
3021     // the element having the least nb of shared links
3022     const SMDS_MeshElement* startElem = 0;
3023     int minNbLinks = 4;
3024     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
3025       int nbLinks = (*itEL).second.size();
3026       if ( nbLinks < minNbLinks ) {
3027         startElem = (*itEL).first;
3028         minNbLinks = nbLinks;
3029         if ( minNbLinks == 1 )
3030           break;
3031       }
3032     }
3033
3034     // search elements to fuse starting from startElem or links of elements
3035     // fused earlyer - startLinks
3036     list< SMESH_TLink > startLinks;
3037     while ( startElem || !startLinks.empty() ) {
3038       while ( !startElem && !startLinks.empty() ) {
3039         // Get an element to start, by a link
3040         SMESH_TLink linkId = startLinks.front();
3041         startLinks.pop_front();
3042         itLE = mapLi_listEl.find( linkId );
3043         if ( itLE != mapLi_listEl.end() ) {
3044           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
3045           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
3046           for ( ; itE != listElem.end() ; itE++ )
3047             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
3048               startElem = (*itE);
3049           mapLi_listEl.erase( itLE );
3050         }
3051       }
3052
3053       if ( startElem ) {
3054         // Get candidates to be fused
3055         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
3056         const SMESH_TLink *link12, *link13;
3057         startElem = 0;
3058         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
3059         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
3060         ASSERT( !setLi.empty() );
3061         set< SMESH_TLink >::iterator itLi;
3062         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
3063         {
3064           const SMESH_TLink & link = (*itLi);
3065           itLE = mapLi_listEl.find( link );
3066           if ( itLE == mapLi_listEl.end() )
3067             continue;
3068
3069           const SMDS_MeshElement* elem = (*itLE).second.front();
3070           if ( elem == tr1 )
3071             elem = (*itLE).second.back();
3072           mapLi_listEl.erase( itLE );
3073           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
3074             continue;
3075           if ( tr2 ) {
3076             tr3 = elem;
3077             link13 = &link;
3078           }
3079           else {
3080             tr2 = elem;
3081             link12 = &link;
3082           }
3083
3084           // add other links of elem to list of links to re-start from
3085           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
3086           set< SMESH_TLink >::iterator it;
3087           for ( it = links.begin(); it != links.end(); it++ ) {
3088             const SMESH_TLink& link2 = (*it);
3089             if ( link2 != link )
3090               startLinks.push_back( link2 );
3091           }
3092         }
3093
3094         // Get nodes of possible quadrangles
3095         const SMDS_MeshNode *n12 [4], *n13 [4];
3096         bool Ok12 = false, Ok13 = false;
3097         const SMDS_MeshNode *linkNode1, *linkNode2;
3098         if(tr2) {
3099           linkNode1 = link12->first;
3100           linkNode2 = link12->second;
3101           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
3102             Ok12 = true;
3103         }
3104         if(tr3) {
3105           linkNode1 = link13->first;
3106           linkNode2 = link13->second;
3107           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
3108             Ok13 = true;
3109         }
3110
3111         // Choose a pair to fuse
3112         if ( Ok12 && Ok13 ) {
3113           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
3114           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
3115           double aBadRate12 = getBadRate( &quad12, theCrit );
3116           double aBadRate13 = getBadRate( &quad13, theCrit );
3117           if (  aBadRate13 < aBadRate12 )
3118             Ok12 = false;
3119           else
3120             Ok13 = false;
3121         }
3122
3123         // Make quadrangles
3124         // and remove fused elems and remove links from the maps
3125         mapEl_setLi.erase( tr1 );
3126         if ( Ok12 )
3127         {
3128           mapEl_setLi.erase( tr2 );
3129           mapLi_listEl.erase( *link12 );
3130           if ( tr1->NbNodes() == 3 )
3131           {
3132             const SMDS_MeshElement* newElem = 0;
3133             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
3134             myLastCreatedElems.Append(newElem);
3135             AddToSameGroups( newElem, tr1, aMesh );
3136             int aShapeId = tr1->getshapeId();
3137             if ( aShapeId )
3138               aMesh->SetMeshElementOnShape( newElem, aShapeId );
3139             aMesh->RemoveElement( tr1 );
3140             aMesh->RemoveElement( tr2 );
3141           }
3142           else {
3143             vector< const SMDS_MeshNode* > N1;
3144             vector< const SMDS_MeshNode* > N2;
3145             getNodesFromTwoTria(tr1,tr2,N1,N2);
3146             // now we receive following N1 and N2 (using numeration as in image in InverseDiag())
3147             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
3148             // i.e. first nodes from both arrays form a new diagonal
3149             const SMDS_MeshNode* aNodes[8];
3150             aNodes[0] = N1[0];
3151             aNodes[1] = N1[1];
3152             aNodes[2] = N2[0];
3153             aNodes[3] = N2[1];
3154             aNodes[4] = N1[3];
3155             aNodes[5] = N2[5];
3156             aNodes[6] = N2[3];
3157             aNodes[7] = N1[5];
3158             const SMDS_MeshElement* newElem = 0;
3159             if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
3160               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
3161                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
3162             else
3163               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
3164                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
3165             myLastCreatedElems.Append(newElem);
3166             AddToSameGroups( newElem, tr1, aMesh );
3167             int aShapeId = tr1->getshapeId();
3168             if ( aShapeId )
3169               aMesh->SetMeshElementOnShape( newElem, aShapeId );
3170             aMesh->RemoveElement( tr1 );
3171             aMesh->RemoveElement( tr2 );
3172             // remove middle node (9)
3173             if ( N1[4]->NbInverseElements() == 0 )
3174               aMesh->RemoveNode( N1[4] );
3175             if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
3176               aMesh->RemoveNode( N1[6] );
3177             if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
3178               aMesh->RemoveNode( N2[6] );
3179           }
3180         }
3181         else if ( Ok13 )
3182         {
3183           mapEl_setLi.erase( tr3 );
3184           mapLi_listEl.erase( *link13 );
3185           if ( tr1->NbNodes() == 3 ) {
3186             const SMDS_MeshElement* newElem = 0;
3187             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
3188             myLastCreatedElems.Append(newElem);
3189             AddToSameGroups( newElem, tr1, aMesh );
3190             int aShapeId = tr1->getshapeId();
3191             if ( aShapeId )
3192               aMesh->SetMeshElementOnShape( newElem, aShapeId );
3193             aMesh->RemoveElement( tr1 );
3194             aMesh->RemoveElement( tr3 );
3195           }
3196           else {
3197             vector< const SMDS_MeshNode* > N1;
3198             vector< const SMDS_MeshNode* > N2;
3199             getNodesFromTwoTria(tr1,tr3,N1,N2);
3200             // now we receive following N1 and N2 (using numeration as above image)
3201             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
3202             // i.e. first nodes from both arrays form a new diagonal
3203             const SMDS_MeshNode* aNodes[8];
3204             aNodes[0] = N1[0];
3205             aNodes[1] = N1[1];
3206             aNodes[2] = N2[0];
3207             aNodes[3] = N2[1];
3208             aNodes[4] = N1[3];
3209             aNodes[5] = N2[5];
3210             aNodes[6] = N2[3];
3211             aNodes[7] = N1[5];
3212             const SMDS_MeshElement* newElem = 0;
3213             if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
3214               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
3215                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
3216             else
3217               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
3218                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
3219             myLastCreatedElems.Append(newElem);
3220             AddToSameGroups( newElem, tr1, aMesh );
3221             int aShapeId = tr1->getshapeId();
3222             if ( aShapeId )
3223               aMesh->SetMeshElementOnShape( newElem, aShapeId );
3224             aMesh->RemoveElement( tr1 );
3225             aMesh->RemoveElement( tr3 );
3226             // remove middle node (9)
3227             if ( N1[4]->NbInverseElements() == 0 )
3228               aMesh->RemoveNode( N1[4] );
3229             if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
3230               aMesh->RemoveNode( N1[6] );
3231             if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
3232               aMesh->RemoveNode( N2[6] );
3233           }
3234         }
3235
3236         // Next element to fuse: the rejected one
3237         if ( tr3 )
3238           startElem = Ok12 ? tr3 : tr2;
3239
3240       } // if ( startElem )
3241     } // while ( startElem || !startLinks.empty() )
3242   } // while ( ! mapEl_setLi.empty() )
3243
3244   return true;
3245 }
3246
3247
3248 /*#define DUMPSO(txt) \
3249 //  cout << txt << endl;
3250 //=============================================================================
3251 //
3252 //
3253 //
3254 //=============================================================================
3255 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
3256 {
3257 if ( i1 == i2 )
3258 return;
3259 int tmp = idNodes[ i1 ];
3260 idNodes[ i1 ] = idNodes[ i2 ];
3261 idNodes[ i2 ] = tmp;
3262 gp_Pnt Ptmp = P[ i1 ];
3263 P[ i1 ] = P[ i2 ];
3264 P[ i2 ] = Ptmp;
3265 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
3266 }
3267
3268 //=======================================================================
3269 //function : SortQuadNodes
3270 //purpose  : Set 4 nodes of a quadrangle face in a good order.
3271 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
3272 //           1 or 2 else 0.
3273 //=======================================================================
3274
3275 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
3276 int               idNodes[] )
3277 {
3278   gp_Pnt P[4];
3279   int i;
3280   for ( i = 0; i < 4; i++ ) {
3281     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
3282     if ( !n ) return 0;
3283     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
3284   }
3285
3286   gp_Vec V1(P[0], P[1]);
3287   gp_Vec V2(P[0], P[2]);
3288   gp_Vec V3(P[0], P[3]);
3289
3290   gp_Vec Cross1 = V1 ^ V2;
3291   gp_Vec Cross2 = V2 ^ V3;
3292
3293   i = 0;
3294   if (Cross1.Dot(Cross2) < 0)
3295   {
3296     Cross1 = V2 ^ V1;
3297     Cross2 = V1 ^ V3;
3298
3299     if (Cross1.Dot(Cross2) < 0)
3300       i = 2;
3301     else
3302       i = 1;
3303     swap ( i, i + 1, idNodes, P );
3304
3305     //     for ( int ii = 0; ii < 4; ii++ ) {
3306     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
3307     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
3308     //     }
3309   }
3310   return i;
3311 }
3312
3313 //=======================================================================
3314 //function : SortHexaNodes
3315 //purpose  : Set 8 nodes of a hexahedron in a good order.
3316 //           Return success status
3317 //=======================================================================
3318
3319 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
3320                                       int               idNodes[] )
3321 {
3322   gp_Pnt P[8];
3323   int i;
3324   DUMPSO( "INPUT: ========================================");
3325   for ( i = 0; i < 8; i++ ) {
3326     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
3327     if ( !n ) return false;
3328     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
3329     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
3330   }
3331   DUMPSO( "========================================");
3332
3333
3334   set<int> faceNodes;  // ids of bottom face nodes, to be found
3335   set<int> checkedId1; // ids of tried 2-nd nodes
3336   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
3337   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
3338   int iMin, iLoop1 = 0;
3339
3340   // Loop to try the 2-nd nodes
3341
3342   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
3343   {
3344     // Find not checked 2-nd node
3345     for ( i = 1; i < 8; i++ )
3346       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
3347         int id1 = idNodes[i];
3348         swap ( 1, i, idNodes, P );
3349         checkedId1.insert ( id1 );
3350         break;
3351       }
3352
3353     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
3354     // ie that all but meybe one (id3 which is on the same face) nodes
3355     // lay on the same side from the triangle plane.
3356
3357     bool manyInPlane = false; // more than 4 nodes lay in plane
3358     int iLoop2 = 0;
3359     while ( ++iLoop2 < 6 ) {
3360
3361       // get 1-2-3 plane coeffs
3362       Standard_Real A, B, C, D;
3363       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
3364       if ( N.SquareMagnitude() > gp::Resolution() )
3365       {
3366         gp_Pln pln ( P[0], N );
3367         pln.Coefficients( A, B, C, D );
3368
3369         // find the node (iMin) closest to pln
3370         Standard_Real dist[ 8 ], minDist = DBL_MAX;
3371         set<int> idInPln;
3372         for ( i = 3; i < 8; i++ ) {
3373           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
3374           if ( fabs( dist[i] ) < minDist ) {
3375             minDist = fabs( dist[i] );
3376             iMin = i;
3377           }
3378           if ( fabs( dist[i] ) <= tol )
3379             idInPln.insert( idNodes[i] );
3380         }
3381
3382         // there should not be more than 4 nodes in bottom plane
3383         if ( idInPln.size() > 1 )
3384         {
3385           DUMPSO( "### idInPln.size() = " << idInPln.size());
3386           // idInPlane does not contain the first 3 nodes
3387           if ( manyInPlane || idInPln.size() == 5)
3388             return false; // all nodes in one plane
3389           manyInPlane = true;
3390
3391           // set the 1-st node to be not in plane
3392           for ( i = 3; i < 8; i++ ) {
3393             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
3394               DUMPSO( "### Reset 0-th node");
3395               swap( 0, i, idNodes, P );
3396               break;
3397             }
3398           }
3399
3400           // reset to re-check second nodes
3401           leastDist = DBL_MAX;
3402           faceNodes.clear();
3403           checkedId1.clear();
3404           iLoop1 = 0;
3405           break; // from iLoop2;
3406         }
3407
3408         // check that the other 4 nodes are on the same side
3409         bool sameSide = true;
3410         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
3411         for ( i = 3; sameSide && i < 8; i++ ) {
3412           if ( i != iMin )
3413             sameSide = ( isNeg == dist[i] <= 0.);
3414         }
3415
3416         // keep best solution
3417         if ( sameSide && minDist < leastDist ) {
3418           leastDist = minDist;
3419           faceNodes.clear();
3420           faceNodes.insert( idNodes[ 1 ] );
3421           faceNodes.insert( idNodes[ 2 ] );
3422           faceNodes.insert( idNodes[ iMin ] );
3423           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
3424                   << " leastDist = " << leastDist);
3425           if ( leastDist <= DBL_MIN )
3426             break;
3427         }
3428       }
3429
3430       // set next 3-d node to check
3431       int iNext = 2 + iLoop2;
3432       if ( iNext < 8 ) {
3433         DUMPSO( "Try 2-nd");
3434         swap ( 2, iNext, idNodes, P );
3435       }
3436     } // while ( iLoop2 < 6 )
3437   } // iLoop1
3438
3439   if ( faceNodes.empty() ) return false;
3440
3441   // Put the faceNodes in proper places
3442   for ( i = 4; i < 8; i++ ) {
3443     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
3444       // find a place to put
3445       int iTo = 1;
3446       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
3447         iTo++;
3448       DUMPSO( "Set faceNodes");
3449       swap ( iTo, i, idNodes, P );
3450     }
3451   }
3452
3453
3454   // Set nodes of the found bottom face in good order
3455   DUMPSO( " Found bottom face: ");
3456   i = SortQuadNodes( theMesh, idNodes );
3457   if ( i ) {
3458     gp_Pnt Ptmp = P[ i ];
3459     P[ i ] = P[ i+1 ];
3460     P[ i+1 ] = Ptmp;
3461   }
3462   //   else
3463   //     for ( int ii = 0; ii < 4; ii++ ) {
3464   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
3465   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
3466   //    }
3467
3468   // Gravity center of the top and bottom faces
3469   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
3470   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
3471
3472   // Get direction from the bottom to the top face
3473   gp_Vec upDir ( aGCb, aGCt );
3474   Standard_Real upDirSize = upDir.Magnitude();
3475   if ( upDirSize <= gp::Resolution() ) return false;
3476   upDir / upDirSize;
3477
3478   // Assure that the bottom face normal points up
3479   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
3480   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
3481   if ( Nb.Dot( upDir ) < 0 ) {
3482     DUMPSO( "Reverse bottom face");
3483     swap( 1, 3, idNodes, P );
3484   }
3485
3486   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
3487   Standard_Real minDist = DBL_MAX;
3488   for ( i = 4; i < 8; i++ ) {
3489     // projection of P[i] to the plane defined by P[0] and upDir
3490     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
3491     Standard_Real sqDist = P[0].SquareDistance( Pp );
3492     if ( sqDist < minDist ) {
3493       minDist = sqDist;
3494       iMin = i;
3495     }
3496   }
3497   DUMPSO( "Set 4-th");
3498   swap ( 4, iMin, idNodes, P );
3499
3500   // Set nodes of the top face in good order
3501   DUMPSO( "Sort top face");
3502   i = SortQuadNodes( theMesh, &idNodes[4] );
3503   if ( i ) {
3504     i += 4;
3505     gp_Pnt Ptmp = P[ i ];
3506     P[ i ] = P[ i+1 ];
3507     P[ i+1 ] = Ptmp;
3508   }
3509
3510   // Assure that direction of the top face normal is from the bottom face
3511   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
3512   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
3513   if ( Nt.Dot( upDir ) < 0 ) {
3514     DUMPSO( "Reverse top face");
3515     swap( 5, 7, idNodes, P );
3516   }
3517
3518   //   DUMPSO( "OUTPUT: ========================================");
3519   //   for ( i = 0; i < 8; i++ ) {
3520   //     float *p = ugrid->GetPoint(idNodes[i]);
3521   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
3522   //   }
3523
3524   return true;
3525 }*/
3526
3527 //================================================================================
3528 /*!
3529  * \brief Return nodes linked to the given one
3530  * \param theNode - the node
3531  * \param linkedNodes - the found nodes
3532  * \param type - the type of elements to check
3533  *
3534  * Medium nodes are ignored
3535  */
3536 //================================================================================
3537
3538 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
3539                                        TIDSortedElemSet &   linkedNodes,
3540                                        SMDSAbs_ElementType  type )
3541 {
3542   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
3543   while ( elemIt->more() )
3544   {
3545     const SMDS_MeshElement* elem = elemIt->next();
3546     if(elem->GetType() == SMDSAbs_0DElement)
3547       continue;
3548
3549     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
3550     if ( elem->GetType() == SMDSAbs_Volume )
3551     {
3552       SMDS_VolumeTool vol( elem );
3553       while ( nodeIt->more() ) {
3554         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
3555         if ( theNode != n && vol.IsLinked( theNode, n ))
3556           linkedNodes.insert( n );
3557       }
3558     }
3559     else
3560     {
3561       for ( int i = 0; nodeIt->more(); ++i ) {
3562         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
3563         if ( n == theNode ) {
3564           int iBefore = i - 1;
3565           int iAfter  = i + 1;
3566           if ( elem->IsQuadratic() ) {
3567             int nb = elem->NbNodes() / 2;
3568             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
3569             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
3570           }
3571           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
3572           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
3573         }
3574       }
3575     }
3576   }
3577 }
3578
3579 //=======================================================================
3580 //function : laplacianSmooth
3581 //purpose  : pulls theNode toward the center of surrounding nodes directly
3582 //           connected to that node along an element edge
3583 //=======================================================================
3584
3585 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
3586                      const Handle(Geom_Surface)&          theSurface,
3587                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3588 {
3589   // find surrounding nodes
3590
3591   TIDSortedElemSet nodeSet;
3592   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
3593
3594   // compute new coodrs
3595
3596   double coord[] = { 0., 0., 0. };
3597   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
3598   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
3599     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
3600     if ( theSurface.IsNull() ) { // smooth in 3D
3601       coord[0] += node->X();
3602       coord[1] += node->Y();
3603       coord[2] += node->Z();
3604     }
3605     else { // smooth in 2D
3606       ASSERT( theUVMap.find( node ) != theUVMap.end() );
3607       gp_XY* uv = theUVMap[ node ];
3608       coord[0] += uv->X();
3609       coord[1] += uv->Y();
3610     }
3611   }
3612   int nbNodes = nodeSet.size();
3613   if ( !nbNodes )
3614     return;
3615   coord[0] /= nbNodes;
3616   coord[1] /= nbNodes;
3617
3618   if ( !theSurface.IsNull() ) {
3619     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
3620     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
3621     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
3622     coord[0] = p3d.X();
3623     coord[1] = p3d.Y();
3624     coord[2] = p3d.Z();
3625   }
3626   else
3627     coord[2] /= nbNodes;
3628
3629   // move node
3630
3631   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
3632 }
3633
3634 //=======================================================================
3635 //function : centroidalSmooth
3636 //purpose  : pulls theNode toward the element-area-weighted centroid of the
3637 //           surrounding elements
3638 //=======================================================================
3639
3640 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
3641                       const Handle(Geom_Surface)&          theSurface,
3642                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3643 {
3644   gp_XYZ aNewXYZ(0.,0.,0.);
3645   SMESH::Controls::Area anAreaFunc;
3646   double totalArea = 0.;
3647   int nbElems = 0;
3648
3649   // compute new XYZ
3650
3651   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
3652   while ( elemIt->more() )
3653   {
3654     const SMDS_MeshElement* elem = elemIt->next();
3655     nbElems++;
3656
3657     gp_XYZ elemCenter(0.,0.,0.);
3658     SMESH::Controls::TSequenceOfXYZ aNodePoints;
3659     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3660     int nn = elem->NbNodes();
3661     if(elem->IsQuadratic()) nn = nn/2;
3662     int i=0;
3663     //while ( itN->more() ) {
3664     while ( i<nn ) {
3665       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
3666       i++;
3667       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
3668       aNodePoints.push_back( aP );
3669       if ( !theSurface.IsNull() ) { // smooth in 2D
3670         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
3671         gp_XY* uv = theUVMap[ aNode ];
3672         aP.SetCoord( uv->X(), uv->Y(), 0. );
3673       }
3674       elemCenter += aP;
3675     }
3676     double elemArea = anAreaFunc.GetValue( aNodePoints );
3677     totalArea += elemArea;
3678     elemCenter /= nn;
3679     aNewXYZ += elemCenter * elemArea;
3680   }
3681   aNewXYZ /= totalArea;
3682   if ( !theSurface.IsNull() ) {
3683     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
3684     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
3685   }
3686
3687   // move node
3688
3689   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
3690 }
3691
3692 //=======================================================================
3693 //function : getClosestUV
3694 //purpose  : return UV of closest projection
3695 //=======================================================================
3696
3697 static bool getClosestUV (Extrema_GenExtPS& projector,
3698                           const gp_Pnt&     point,
3699                           gp_XY &           result)
3700 {
3701   projector.Perform( point );
3702   if ( projector.IsDone() ) {
3703     double u, v, minVal = DBL_MAX;
3704     for ( int i = projector.NbExt(); i > 0; i-- )
3705       if ( projector.SquareDistance( i ) < minVal ) {
3706         minVal = projector.SquareDistance( i );
3707         projector.Point( i ).Parameter( u, v );
3708       }
3709     result.SetCoord( u, v );
3710     return true;
3711   }
3712   return false;
3713 }
3714
3715 //=======================================================================
3716 //function : Smooth
3717 //purpose  : Smooth theElements during theNbIterations or until a worst
3718 //           element has aspect ratio <= theTgtAspectRatio.
3719 //           Aspect Ratio varies in range [1.0, inf].
3720 //           If theElements is empty, the whole mesh is smoothed.
3721 //           theFixedNodes contains additionally fixed nodes. Nodes built
3722 //           on edges and boundary nodes are always fixed.
3723 //=======================================================================
3724
3725 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
3726                                set<const SMDS_MeshNode*> & theFixedNodes,
3727                                const SmoothMethod          theSmoothMethod,
3728                                const int                   theNbIterations,
3729                                double                      theTgtAspectRatio,
3730                                const bool                  the2D)
3731 {
3732   myLastCreatedElems.Clear();
3733   myLastCreatedNodes.Clear();
3734
3735   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
3736
3737   if ( theTgtAspectRatio < 1.0 )
3738     theTgtAspectRatio = 1.0;
3739
3740   const double disttol = 1.e-16;
3741
3742   SMESH::Controls::AspectRatio aQualityFunc;
3743
3744   SMESHDS_Mesh* aMesh = GetMeshDS();
3745
3746   if ( theElems.empty() ) {
3747     // add all faces to theElems
3748     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
3749     while ( fIt->more() ) {
3750       const SMDS_MeshElement* face = fIt->next();
3751       theElems.insert( theElems.end(), face );
3752     }
3753   }
3754   // get all face ids theElems are on
3755   set< int > faceIdSet;
3756   TIDSortedElemSet::iterator itElem;
3757   if ( the2D )
3758     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3759       int fId = FindShape( *itElem );
3760       // check that corresponding submesh exists and a shape is face
3761       if (fId &&
3762           faceIdSet.find( fId ) == faceIdSet.end() &&
3763           aMesh->MeshElements( fId )) {
3764         TopoDS_Shape F = aMesh->IndexToShape( fId );
3765         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
3766           faceIdSet.insert( fId );
3767       }
3768     }
3769   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
3770
3771   // ===============================================
3772   // smooth elements on each TopoDS_Face separately
3773   // ===============================================
3774
3775   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
3776   for ( ; fId != faceIdSet.rend(); ++fId ) {
3777     // get face surface and submesh
3778     Handle(Geom_Surface) surface;
3779     SMESHDS_SubMesh* faceSubMesh = 0;
3780     TopoDS_Face face;
3781     double fToler2 = 0, f,l;
3782     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
3783     bool isUPeriodic = false, isVPeriodic = false;
3784     if ( *fId ) {
3785       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
3786       surface = BRep_Tool::Surface( face );
3787       faceSubMesh = aMesh->MeshElements( *fId );
3788       fToler2 = BRep_Tool::Tolerance( face );
3789       fToler2 *= fToler2 * 10.;
3790       isUPeriodic = surface->IsUPeriodic();
3791       if ( isUPeriodic )
3792         surface->UPeriod();
3793       isVPeriodic = surface->IsVPeriodic();
3794       if ( isVPeriodic )
3795         surface->VPeriod();
3796       surface->Bounds( u1, u2, v1, v2 );
3797     }
3798     // ---------------------------------------------------------
3799     // for elements on a face, find movable and fixed nodes and
3800     // compute UV for them
3801     // ---------------------------------------------------------
3802     bool checkBoundaryNodes = false;
3803     bool isQuadratic = false;
3804     set<const SMDS_MeshNode*> setMovableNodes;
3805     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3806     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3807     list< const SMDS_MeshElement* > elemsOnFace;
3808
3809     Extrema_GenExtPS projector;
3810     GeomAdaptor_Surface surfAdaptor;
3811     if ( !surface.IsNull() ) {
3812       surfAdaptor.Load( surface );
3813       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3814     }
3815     int nbElemOnFace = 0;
3816     itElem = theElems.begin();
3817     // loop on not yet smoothed elements: look for elems on a face
3818     while ( itElem != theElems.end() ) {
3819       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3820         break; // all elements found
3821
3822       const SMDS_MeshElement* elem = *itElem;
3823       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3824            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3825         ++itElem;
3826         continue;
3827       }
3828       elemsOnFace.push_back( elem );
3829       theElems.erase( itElem++ );
3830       nbElemOnFace++;
3831
3832       if ( !isQuadratic )
3833         isQuadratic = elem->IsQuadratic();
3834
3835       // get movable nodes of elem
3836       const SMDS_MeshNode* node;
3837       SMDS_TypeOfPosition posType;
3838       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3839       int nn = 0, nbn =  elem->NbNodes();
3840       if(elem->IsQuadratic())
3841         nbn = nbn/2;
3842       while ( nn++ < nbn ) {
3843         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3844         const SMDS_PositionPtr& pos = node->GetPosition();
3845         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3846         if (posType != SMDS_TOP_EDGE &&
3847             posType != SMDS_TOP_VERTEX &&
3848             theFixedNodes.find( node ) == theFixedNodes.end())
3849         {
3850           // check if all faces around the node are on faceSubMesh
3851           // because a node on edge may be bound to face
3852           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3853           bool all = true;
3854           if ( faceSubMesh ) {
3855             while ( eIt->more() && all ) {
3856               const SMDS_MeshElement* e = eIt->next();
3857               all = faceSubMesh->Contains( e );
3858             }
3859           }
3860           if ( all )
3861             setMovableNodes.insert( node );
3862           else
3863             checkBoundaryNodes = true;
3864         }
3865         if ( posType == SMDS_TOP_3DSPACE )
3866           checkBoundaryNodes = true;
3867       }
3868
3869       if ( surface.IsNull() )
3870         continue;
3871
3872       // get nodes to check UV
3873       list< const SMDS_MeshNode* > uvCheckNodes;
3874       itN = elem->nodesIterator();
3875       nn = 0; nbn =  elem->NbNodes();
3876       if(elem->IsQuadratic())
3877         nbn = nbn/2;
3878       while ( nn++ < nbn ) {
3879         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3880         if ( uvMap.find( node ) == uvMap.end() )
3881           uvCheckNodes.push_back( node );
3882         // add nodes of elems sharing node
3883         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3884         //         while ( eIt->more() ) {
3885         //           const SMDS_MeshElement* e = eIt->next();
3886         //           if ( e != elem ) {
3887         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3888         //             while ( nIt->more() ) {
3889         //               const SMDS_MeshNode* n =
3890         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3891         //               if ( uvMap.find( n ) == uvMap.end() )
3892         //                 uvCheckNodes.push_back( n );
3893         //             }
3894         //           }
3895         //         }
3896       }
3897       // check UV on face
3898       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3899       for ( ; n != uvCheckNodes.end(); ++n ) {
3900         node = *n;
3901         gp_XY uv( 0, 0 );
3902         const SMDS_PositionPtr& pos = node->GetPosition();
3903         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3904         // get existing UV
3905         switch ( posType ) {
3906         case SMDS_TOP_FACE: {
3907           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3908           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3909           break;
3910         }
3911         case SMDS_TOP_EDGE: {
3912           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3913           Handle(Geom2d_Curve) pcurve;
3914           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3915             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3916           if ( !pcurve.IsNull() ) {
3917             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3918             uv = pcurve->Value( u ).XY();
3919           }
3920           break;
3921         }
3922         case SMDS_TOP_VERTEX: {
3923           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3924           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3925             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3926           break;
3927         }
3928         default:;
3929         }
3930         // check existing UV
3931         bool project = true;
3932         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3933         double dist1 = DBL_MAX, dist2 = 0;
3934         if ( posType != SMDS_TOP_3DSPACE ) {
3935           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3936           project = dist1 > fToler2;
3937         }
3938         if ( project ) { // compute new UV
3939           gp_XY newUV;
3940           if ( !getClosestUV( projector, pNode, newUV )) {
3941             MESSAGE("Node Projection Failed " << node);
3942           }
3943           else {
3944             if ( isUPeriodic )
3945               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3946             if ( isVPeriodic )
3947               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3948             // check new UV
3949             if ( posType != SMDS_TOP_3DSPACE )
3950               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3951             if ( dist2 < dist1 )
3952               uv = newUV;
3953           }
3954         }
3955         // store UV in the map
3956         listUV.push_back( uv );
3957         uvMap.insert( make_pair( node, &listUV.back() ));
3958       }
3959     } // loop on not yet smoothed elements
3960
3961     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3962       checkBoundaryNodes = true;
3963
3964     // fix nodes on mesh boundary
3965
3966     if ( checkBoundaryNodes ) {
3967       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3968       map< SMESH_TLink, int >::iterator link_nb;
3969       // put all elements links to linkNbMap
3970       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3971       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3972         const SMDS_MeshElement* elem = (*elemIt);
3973         int nbn =  elem->NbCornerNodes();
3974         // loop on elem links: insert them in linkNbMap
3975         for ( int iN = 0; iN < nbn; ++iN ) {
3976           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3977           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3978           SMESH_TLink link( n1, n2 );
3979           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3980           link_nb->second++;
3981         }
3982       }
3983       // remove nodes that are in links encountered only once from setMovableNodes
3984       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3985         if ( link_nb->second == 1 ) {
3986           setMovableNodes.erase( link_nb->first.node1() );
3987           setMovableNodes.erase( link_nb->first.node2() );
3988         }
3989       }
3990     }
3991
3992     // -----------------------------------------------------
3993     // for nodes on seam edge, compute one more UV ( uvMap2 );
3994     // find movable nodes linked to nodes on seam and which
3995     // are to be smoothed using the second UV ( uvMap2 )
3996     // -----------------------------------------------------
3997
3998     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3999     if ( !surface.IsNull() ) {
4000       TopExp_Explorer eExp( face, TopAbs_EDGE );
4001       for ( ; eExp.More(); eExp.Next() ) {
4002         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
4003         if ( !BRep_Tool::IsClosed( edge, face ))
4004           continue;
4005         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
4006         if ( !sm ) continue;
4007         // find out which parameter varies for a node on seam
4008         double f,l;
4009         gp_Pnt2d uv1, uv2;
4010         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
4011         if ( pcurve.IsNull() ) continue;
4012         uv1 = pcurve->Value( f );
4013         edge.Reverse();
4014         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
4015         if ( pcurve.IsNull() ) continue;
4016         uv2 = pcurve->Value( f );
4017         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
4018         // assure uv1 < uv2
4019         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
4020           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
4021         }
4022         // get nodes on seam and its vertices
4023         list< const SMDS_MeshNode* > seamNodes;
4024         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
4025         while ( nSeamIt->more() ) {
4026           const SMDS_MeshNode* node = nSeamIt->next();
4027           if ( !isQuadratic || !IsMedium( node ))
4028             seamNodes.push_back( node );
4029         }
4030         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
4031         for ( ; vExp.More(); vExp.Next() ) {
4032           sm = aMesh->MeshElements( vExp.Current() );
4033           if ( sm ) {
4034             nSeamIt = sm->GetNodes();
4035             while ( nSeamIt->more() )
4036               seamNodes.push_back( nSeamIt->next() );
4037           }
4038         }
4039         // loop on nodes on seam
4040         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
4041         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
4042           const SMDS_MeshNode* nSeam = *noSeIt;
4043           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
4044           if ( n_uv == uvMap.end() )
4045             continue;
4046           // set the first UV
4047           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
4048           // set the second UV
4049           listUV.push_back( *n_uv->second );
4050           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
4051           if ( uvMap2.empty() )
4052             uvMap2 = uvMap; // copy the uvMap contents
4053           uvMap2[ nSeam ] = &listUV.back();
4054
4055           // collect movable nodes linked to ones on seam in nodesNearSeam
4056           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
4057           while ( eIt->more() ) {
4058             const SMDS_MeshElement* e = eIt->next();
4059             int nbUseMap1 = 0, nbUseMap2 = 0;
4060             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
4061             int nn = 0, nbn =  e->NbNodes();
4062             if(e->IsQuadratic()) nbn = nbn/2;
4063             while ( nn++ < nbn )
4064             {
4065               const SMDS_MeshNode* n =
4066                 static_cast<const SMDS_MeshNode*>( nIt->next() );
4067               if (n == nSeam ||
4068                   setMovableNodes.find( n ) == setMovableNodes.end() )
4069                 continue;
4070               // add only nodes being closer to uv2 than to uv1
4071               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
4072                            0.5 * ( n->Y() + nSeam->Y() ),
4073                            0.5 * ( n->Z() + nSeam->Z() ));
4074               gp_XY uv;
4075               getClosestUV( projector, pMid, uv );
4076               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
4077                 nodesNearSeam.insert( n );
4078                 nbUseMap2++;
4079               }
4080               else
4081                 nbUseMap1++;
4082             }
4083             // for centroidalSmooth all element nodes must
4084             // be on one side of a seam
4085             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
4086               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
4087               nn = 0;
4088               while ( nn++ < nbn ) {
4089                 const SMDS_MeshNode* n =
4090                   static_cast<const SMDS_MeshNode*>( nIt->next() );
4091                 setMovableNodes.erase( n );
4092               }
4093             }
4094           }
4095         } // loop on nodes on seam
4096       } // loop on edge of a face
4097     } // if ( !face.IsNull() )
4098
4099     if ( setMovableNodes.empty() ) {
4100       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
4101       continue; // goto next face
4102     }
4103
4104     // -------------
4105     // SMOOTHING //
4106     // -------------
4107
4108     int it = -1;
4109     double maxRatio = -1., maxDisplacement = -1.;
4110     set<const SMDS_MeshNode*>::iterator nodeToMove;
4111     for ( it = 0; it < theNbIterations; it++ ) {
4112       maxDisplacement = 0.;
4113       nodeToMove = setMovableNodes.begin();
4114       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
4115         const SMDS_MeshNode* node = (*nodeToMove);
4116         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
4117
4118         // smooth
4119         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
4120         if ( theSmoothMethod == LAPLACIAN )
4121           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
4122         else
4123           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
4124
4125         // node displacement
4126         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
4127         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
4128         if ( aDispl > maxDisplacement )
4129           maxDisplacement = aDispl;
4130       }
4131       // no node movement => exit
4132       //if ( maxDisplacement < 1.e-16 ) {
4133       if ( maxDisplacement < disttol ) {
4134         MESSAGE("-- no node movement --");
4135         break;
4136       }
4137
4138       // check elements quality
4139       maxRatio  = 0;
4140       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
4141       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
4142         const SMDS_MeshElement* elem = (*elemIt);
4143         if ( !elem || elem->GetType() != SMDSAbs_Face )
4144           continue;
4145         SMESH::Controls::TSequenceOfXYZ aPoints;
4146         if ( aQualityFunc.GetPoints( elem, aPoints )) {
4147           double aValue = aQualityFunc.GetValue( aPoints );
4148           if ( aValue > maxRatio )
4149             maxRatio = aValue;
4150         }
4151       }
4152       if ( maxRatio <= theTgtAspectRatio ) {
4153         MESSAGE("-- quality achived --");
4154         break;
4155       }
4156       if (it+1 == theNbIterations) {
4157         MESSAGE("-- Iteration limit exceeded --");
4158       }
4159     } // smoothing iterations
4160
4161     MESSAGE(" Face id: " << *fId <<
4162             " Nb iterstions: " << it <<
4163             " Displacement: " << maxDisplacement <<
4164             " Aspect Ratio " << maxRatio);
4165
4166     // ---------------------------------------
4167     // new nodes positions are computed,
4168     // record movement in DS and set new UV
4169     // ---------------------------------------
4170     nodeToMove = setMovableNodes.begin();
4171     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
4172       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
4173       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
4174       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
4175       if ( node_uv != uvMap.end() ) {
4176         gp_XY* uv = node_uv->second;
4177         node->SetPosition
4178           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
4179       }
4180     }
4181
4182     // move medium nodes of quadratic elements
4183     if ( isQuadratic )
4184     {
4185       SMESH_MesherHelper helper( *GetMesh() );
4186       helper.SetSubShape( face );
4187       vector<const SMDS_MeshNode*> nodes;
4188       bool checkUV;
4189       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
4190       for ( ; elemIt != elemsOnFace.end(); ++elemIt )
4191       {
4192         const SMDS_MeshElement* QF = *elemIt;
4193         if ( QF->IsQuadratic() )
4194         {
4195           nodes.assign( SMDS_MeshElement::iterator( QF->interlacedNodesElemIterator() ),
4196                         SMDS_MeshElement::iterator() );
4197           nodes.push_back( nodes[0] );
4198           gp_Pnt xyz;
4199           for (size_t i = 1; i < nodes.size(); i += 2 ) // i points to a medium node
4200           {
4201             if ( !surface.IsNull() )
4202             {
4203               gp_XY uv1 = helper.GetNodeUV( face, nodes[i-1], nodes[i+1], &checkUV );
4204               gp_XY uv2 = helper.GetNodeUV( face, nodes[i+1], nodes[i-1], &checkUV );
4205               gp_XY uv  = helper.GetMiddleUV( surface, uv1, uv2 );
4206               xyz = surface->Value( uv.X(), uv.Y() );
4207             }
4208             else {
4209               xyz = 0.5 * ( SMESH_TNodeXYZ( nodes[i-1] ) + SMESH_TNodeXYZ( nodes[i+1] ));
4210             }
4211             if (( SMESH_TNodeXYZ( nodes[i] ) - xyz.XYZ() ).Modulus() > disttol )
4212               // we have to move a medium node
4213               aMesh->MoveNode( nodes[i], xyz.X(), xyz.Y(), xyz.Z() );
4214           }
4215         }
4216       }
4217     }
4218
4219   } // loop on face ids
4220
4221 }
4222
4223 //=======================================================================
4224 //function : isReverse
4225 //purpose  : Return true if normal of prevNodes is not co-directied with
4226 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
4227 //           iNotSame is where prevNodes and nextNodes are different.
4228 //           If result is true then future volume orientation is OK
4229 //=======================================================================
4230
4231 static bool isReverse(const SMDS_MeshElement*             face,
4232                       const vector<const SMDS_MeshNode*>& prevNodes,
4233                       const vector<const SMDS_MeshNode*>& nextNodes,
4234                       const int                           iNotSame)
4235 {
4236
4237   SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
4238   SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
4239   gp_XYZ extrDir( pN - pP ), faceNorm;
4240   SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false );
4241
4242   return faceNorm * extrDir < 0.0;
4243 }
4244
4245 //=======================================================================
4246 /*!
4247  * \brief Create elements by sweeping an element
4248  * \param elem - element to sweep
4249  * \param newNodesItVec - nodes generated from each node of the element
4250  * \param newElems - generated elements
4251  * \param nbSteps - number of sweeping steps
4252  * \param srcElements - to append elem for each generated element
4253  */
4254 //=======================================================================
4255
4256 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
4257                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
4258                                     list<const SMDS_MeshElement*>&        newElems,
4259                                     const int                             nbSteps,
4260                                     SMESH_SequenceOfElemPtr&              srcElements)
4261 {
4262   //MESSAGE("sweepElement " << nbSteps);
4263   SMESHDS_Mesh* aMesh = GetMeshDS();
4264
4265   const int           nbNodes = elem->NbNodes();
4266   const int         nbCorners = elem->NbCornerNodes();
4267   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of
4268                                                           polyhedron creation !!! */
4269   // Loop on elem nodes:
4270   // find new nodes and detect same nodes indices
4271   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
4272   vector<const SMDS_MeshNode*> prevNod( nbNodes );
4273   vector<const SMDS_MeshNode*> nextNod( nbNodes );
4274   vector<const SMDS_MeshNode*> midlNod( nbNodes );
4275
4276   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
4277   vector<int> sames(nbNodes);
4278   vector<bool> isSingleNode(nbNodes);
4279
4280   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4281     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
4282     const SMDS_MeshNode*                         node = nnIt->first;
4283     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
4284     if ( listNewNodes.empty() )
4285       return;
4286
4287     itNN   [ iNode ] = listNewNodes.begin();
4288     prevNod[ iNode ] = node;
4289     nextNod[ iNode ] = listNewNodes.front();
4290
4291     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
4292                                                              corner node of linear */
4293     if ( prevNod[ iNode ] != nextNod [ iNode ])
4294       nbDouble += !isSingleNode[iNode];
4295
4296     if( iNode < nbCorners ) { // check corners only
4297       if ( prevNod[ iNode ] == nextNod [ iNode ])
4298         sames[nbSame++] = iNode;
4299       else
4300         iNotSameNode = iNode;
4301     }
4302   }
4303
4304   if ( nbSame == nbNodes || nbSame > 2) {
4305     MESSAGE( " Too many same nodes of element " << elem->GetID() );
4306     return;
4307   }
4308
4309   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
4310   {
4311     // fix nodes order to have bottom normal external
4312     if ( baseType == SMDSEntity_Polygon )
4313     {
4314       std::reverse( itNN.begin(), itNN.end() );
4315       std::reverse( prevNod.begin(), prevNod.end() );
4316       std::reverse( midlNod.begin(), midlNod.end() );
4317       std::reverse( nextNod.begin(), nextNod.end() );
4318       std::reverse( isSingleNode.begin(), isSingleNode.end() );
4319     }
4320     else
4321     {
4322       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
4323       SMDS_MeshCell::applyInterlace( ind, itNN );
4324       SMDS_MeshCell::applyInterlace( ind, prevNod );
4325       SMDS_MeshCell::applyInterlace( ind, nextNod );
4326       SMDS_MeshCell::applyInterlace( ind, midlNod );
4327       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
4328       if ( nbSame > 0 )
4329       {
4330         sames[nbSame] = iNotSameNode;
4331         for ( int j = 0; j <= nbSame; ++j )
4332           for ( size_t i = 0; i < ind.size(); ++i )
4333             if ( ind[i] == sames[j] )
4334             {
4335               sames[j] = i;
4336               break;
4337             }
4338         iNotSameNode = sames[nbSame];
4339       }
4340     }
4341   }
4342
4343   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
4344   if ( nbSame > 0 ) {
4345     iSameNode    = sames[ nbSame-1 ];
4346     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
4347     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
4348     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
4349   }
4350
4351   // make new elements
4352   for (int iStep = 0; iStep < nbSteps; iStep++ )
4353   {
4354     // get next nodes
4355     for ( iNode = 0; iNode < nbNodes; iNode++ )
4356     {
4357       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
4358       nextNod[ iNode ] = *itNN[ iNode ]++;
4359     }
4360
4361     SMDS_MeshElement* aNewElem = 0;
4362     /*if(!elem->IsPoly())*/ {
4363       switch ( baseType ) {
4364       case SMDSEntity_0D:
4365       case SMDSEntity_Node: { // sweep NODE
4366         if ( nbSame == 0 ) {
4367           if ( isSingleNode[0] )
4368             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
4369           else
4370             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
4371         }
4372         else
4373           return;
4374         break;
4375       }
4376       case SMDSEntity_Edge: { // sweep EDGE
4377         if ( nbDouble == 0 )
4378         {
4379           if ( nbSame == 0 ) // ---> quadrangle
4380             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
4381                                       nextNod[ 1 ], nextNod[ 0 ] );
4382           else               // ---> triangle
4383             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
4384                                       nextNod[ iNotSameNode ] );
4385         }
4386         else                 // ---> polygon
4387         {
4388           vector<const SMDS_MeshNode*> poly_nodes;
4389           poly_nodes.push_back( prevNod[0] );
4390           poly_nodes.push_back( prevNod[1] );
4391           if ( prevNod[1] != nextNod[1] )
4392           {
4393             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
4394             poly_nodes.push_back( nextNod[1] );
4395           }
4396           if ( prevNod[0] != nextNod[0] )
4397           {
4398             poly_nodes.push_back( nextNod[0] );
4399             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
4400           }
4401           switch ( poly_nodes.size() ) {
4402           case 3:
4403             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
4404             break;
4405           case 4:
4406             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
4407                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
4408             break;
4409           default:
4410             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
4411           }
4412         }
4413         break;
4414       }
4415       case SMDSEntity_Triangle: // TRIANGLE --->
4416         {
4417           if ( nbDouble > 0 ) break;
4418           if ( nbSame == 0 )       // ---> pentahedron
4419             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
4420                                          nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
4421
4422           else if ( nbSame == 1 )  // ---> pyramid
4423             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
4424                                          nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
4425                                          nextNod[ iSameNode ]);
4426
4427           else // 2 same nodes:       ---> tetrahedron
4428             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
4429                                          nextNod[ iNotSameNode ]);
4430           break;
4431         }
4432       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
4433         {
4434           if ( nbSame == 2 )
4435             return;
4436           if ( nbDouble+nbSame == 2 )
4437           {
4438             if(nbSame==0) {      // ---> quadratic quadrangle
4439               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
4440                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
4441             }
4442             else { //(nbSame==1) // ---> quadratic triangle
4443               if(sames[0]==2) {
4444                 return; // medium node on axis
4445               }
4446               else if(sames[0]==0)
4447                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
4448                                           nextNod[2], midlNod[1], prevNod[2]);
4449               else // sames[0]==1
4450                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
4451                                           midlNod[0], nextNod[2], prevNod[2]);
4452             }
4453           }
4454           else if ( nbDouble == 3 )
4455           {
4456             if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
4457               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
4458                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
4459             }
4460           }
4461           else
4462             return;
4463           break;
4464         }
4465       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
4466         if ( nbDouble > 0 ) break;
4467
4468         if ( nbSame == 0 )       // ---> hexahedron
4469           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
4470                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
4471
4472         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
4473           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
4474                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
4475                                        nextNod[ iSameNode ]);
4476           newElems.push_back( aNewElem );
4477           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
4478                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
4479                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
4480         }
4481         else if ( nbSame == 2 ) { // ---> pentahedron
4482           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
4483             // iBeforeSame is same too
4484             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
4485                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
4486                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
4487           else
4488             // iAfterSame is same too
4489             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
4490                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
4491                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
4492         }
4493         break;
4494       }
4495       case SMDSEntity_Quad_Triangle:  // sweep (Bi)Quadratic TRIANGLE --->
4496       case SMDSEntity_BiQuad_Triangle: /* ??? */ { 
4497         if ( nbDouble+nbSame != 3 ) break;
4498         if(nbSame==0) {
4499           // --->  pentahedron with 15 nodes
4500           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
4501                                        nextNod[0], nextNod[1], nextNod[2],
4502                                        prevNod[3], prevNod[4], prevNod[5],
4503                                        nextNod[3], nextNod[4], nextNod[5],
4504                                        midlNod[0], midlNod[1], midlNod[2]);
4505         }
4506         else if(nbSame==1) {
4507           // --->  2d order pyramid of 13 nodes
4508           int apex = iSameNode;
4509           int i0 = ( apex + 1 ) % nbCorners;
4510           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
4511           int i0a = apex + 3;
4512           int i1a = i1 + 3;
4513           int i01 = i0 + 3;
4514           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
4515                                       nextNod[i0], nextNod[i1], prevNod[apex],
4516                                       prevNod[i01], midlNod[i0],
4517                                       nextNod[i01], midlNod[i1],
4518                                       prevNod[i1a], prevNod[i0a],
4519                                       nextNod[i0a], nextNod[i1a]);
4520         }
4521         else if(nbSame==2) {
4522           // --->  2d order tetrahedron of 10 nodes
4523           int n1 = iNotSameNode;
4524           int n2 = ( n1 + 1             ) % nbCorners;
4525           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
4526           int n12 = n1 + 3;
4527           int n23 = n2 + 3;
4528           int n31 = n3 + 3;
4529           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
4530                                        prevNod[n12], prevNod[n23], prevNod[n31],
4531                                        midlNod[n1], nextNod[n12], nextNod[n31]);
4532         }
4533         break;
4534       }
4535       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
4536         if( nbSame == 0 ) {
4537           if ( nbDouble != 4 ) break;
4538           // --->  hexahedron with 20 nodes
4539           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
4540                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
4541                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
4542                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
4543                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
4544         }
4545         else if(nbSame==1) {
4546           // ---> pyramid + pentahedron - can not be created since it is needed
4547           // additional middle node at the center of face
4548           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
4549           return;
4550         }
4551         else if( nbSame == 2 ) {
4552           if ( nbDouble != 2 ) break;
4553           // --->  2d order Pentahedron with 15 nodes
4554           int n1,n2,n4,n5;
4555           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
4556             // iBeforeSame is same too
4557             n1 = iBeforeSame;
4558             n2 = iOpposSame;
4559             n4 = iSameNode;
4560             n5 = iAfterSame;
4561           }
4562           else {
4563             // iAfterSame is same too
4564             n1 = iSameNode;
4565             n2 = iBeforeSame;
4566             n4 = iAfterSame;
4567             n5 = iOpposSame;
4568           }
4569           int n12 = n2 + 4;
4570           int n45 = n4 + 4;
4571           int n14 = n1 + 4;
4572           int n25 = n5 + 4;
4573           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
4574                                        prevNod[n4], prevNod[n5], nextNod[n5],
4575                                        prevNod[n12], midlNod[n2], nextNod[n12],
4576                                        prevNod[n45], midlNod[n5], nextNod[n45],
4577                                        prevNod[n14], prevNod[n25], nextNod[n25]);
4578         }
4579         break;
4580       }
4581       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
4582
4583         if( nbSame == 0 && nbDouble == 9 ) {
4584           // --->  tri-quadratic hexahedron with 27 nodes
4585           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
4586                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
4587                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
4588                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
4589                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
4590                                        prevNod[8], // bottom center
4591                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
4592                                        nextNod[8], // top center
4593                                        midlNod[8]);// elem center
4594         }
4595         else
4596         {
4597           return;
4598         }
4599         break;
4600       }
4601       case SMDSEntity_Polygon: { // sweep POLYGON
4602
4603         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
4604           // --->  hexagonal prism
4605           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
4606                                        prevNod[3], prevNod[4], prevNod[5],
4607                                        nextNod[0], nextNod[1], nextNod[2],
4608                                        nextNod[3], nextNod[4], nextNod[5]);
4609         }
4610         break;
4611       }
4612       case SMDSEntity_Ball:
4613         return;
4614
4615       default:
4616         break;
4617       }
4618     }
4619
4620     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
4621     {
4622       if ( baseType != SMDSEntity_Polygon )
4623       {
4624         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
4625         SMDS_MeshCell::applyInterlace( ind, prevNod );
4626         SMDS_MeshCell::applyInterlace( ind, nextNod );
4627         SMDS_MeshCell::applyInterlace( ind, midlNod );
4628         SMDS_MeshCell::applyInterlace( ind, itNN );
4629         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
4630         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
4631       }
4632       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
4633       vector<int> quantities (nbNodes + 2);
4634       polyedre_nodes.clear();
4635       quantities.clear();
4636
4637       // bottom of prism
4638       for (int inode = 0; inode < nbNodes; inode++)
4639         polyedre_nodes.push_back( prevNod[inode] );
4640       quantities.push_back( nbNodes );
4641
4642       // top of prism
4643       polyedre_nodes.push_back( nextNod[0] );
4644       for (int inode = nbNodes; inode-1; --inode )
4645         polyedre_nodes.push_back( nextNod[inode-1] );
4646       quantities.push_back( nbNodes );
4647
4648       // side faces
4649       for (int iface = 0; iface < nbNodes; iface++)
4650       {
4651         const int prevNbNodes = polyedre_nodes.size();
4652         int inextface = (iface+1) % nbNodes;
4653         polyedre_nodes.push_back( prevNod[inextface] );
4654         polyedre_nodes.push_back( prevNod[iface] );
4655         if ( prevNod[iface] != nextNod[iface] )
4656         {
4657           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
4658           polyedre_nodes.push_back( nextNod[iface] );
4659         }
4660         if ( prevNod[inextface] != nextNod[inextface] )
4661         {
4662           polyedre_nodes.push_back( nextNod[inextface] );
4663           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
4664         }
4665         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
4666         if ( nbFaceNodes > 2 )
4667           quantities.push_back( nbFaceNodes );
4668         else // degenerated face
4669           polyedre_nodes.resize( prevNbNodes );
4670       }
4671       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
4672     }
4673
4674     if ( aNewElem ) {
4675       newElems.push_back( aNewElem );
4676       myLastCreatedElems.Append(aNewElem);
4677       srcElements.Append( elem );
4678     }
4679
4680     // set new prev nodes
4681     for ( iNode = 0; iNode < nbNodes; iNode++ )
4682       prevNod[ iNode ] = nextNod[ iNode ];
4683
4684   } // for steps
4685 }
4686
4687 //=======================================================================
4688 /*!
4689  * \brief Create 1D and 2D elements around swept elements
4690  * \param mapNewNodes - source nodes and ones generated from them
4691  * \param newElemsMap - source elements and ones generated from them
4692  * \param elemNewNodesMap - nodes generated from each node of each element
4693  * \param elemSet - all swept elements
4694  * \param nbSteps - number of sweeping steps
4695  * \param srcElements - to append elem for each generated element
4696  */
4697 //=======================================================================
4698
4699 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
4700                                   TTElemOfElemListMap &    newElemsMap,
4701                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
4702                                   TIDSortedElemSet&        elemSet,
4703                                   const int                nbSteps,
4704                                   SMESH_SequenceOfElemPtr& srcElements)
4705 {
4706   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
4707   SMESHDS_Mesh* aMesh = GetMeshDS();
4708
4709   // Find nodes belonging to only one initial element - sweep them into edges.
4710
4711   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
4712   for ( ; nList != mapNewNodes.end(); nList++ )
4713   {
4714     const SMDS_MeshNode* node =
4715       static_cast<const SMDS_MeshNode*>( nList->first );
4716     if ( newElemsMap.count( node ))
4717       continue; // node was extruded into edge
4718     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
4719     int nbInitElems = 0;
4720     const SMDS_MeshElement* el = 0;
4721     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
4722     while ( eIt->more() && nbInitElems < 2 ) {
4723       el = eIt->next();
4724       SMDSAbs_ElementType type = el->GetType();
4725       if ( type == SMDSAbs_Volume || type < highType ) continue;
4726       if ( type > highType ) {
4727         nbInitElems = 0;
4728         highType = type;
4729       }
4730       nbInitElems += elemSet.count(el);
4731     }
4732     if ( nbInitElems < 2 ) {
4733       bool NotCreateEdge = el && el->IsMediumNode(node);
4734       if(!NotCreateEdge) {
4735         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
4736         list<const SMDS_MeshElement*> newEdges;
4737         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
4738       }
4739     }
4740   }
4741
4742   // Make a ceiling for each element ie an equal element of last new nodes.
4743   // Find free links of faces - make edges and sweep them into faces.
4744
4745   TTElemOfElemListMap::iterator  itElem      = newElemsMap.begin();
4746   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
4747   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
4748   {
4749     const SMDS_MeshElement* elem = itElem->first;
4750     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
4751
4752     if(itElem->second.size()==0) continue;
4753
4754     const bool isQuadratic = elem->IsQuadratic();
4755
4756     if ( elem->GetType() == SMDSAbs_Edge ) {
4757       // create a ceiling edge
4758       if ( !isQuadratic ) {
4759         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4760                                vecNewNodes[ 1 ]->second.back())) {
4761           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4762                                                    vecNewNodes[ 1 ]->second.back()));
4763           srcElements.Append( elem );
4764         }
4765       }
4766       else {
4767         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4768                                vecNewNodes[ 1 ]->second.back(),
4769                                vecNewNodes[ 2 ]->second.back())) {
4770           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4771                                                    vecNewNodes[ 1 ]->second.back(),
4772                                                    vecNewNodes[ 2 ]->second.back()));
4773           srcElements.Append( elem );
4774         }
4775       }
4776     }
4777     if ( elem->GetType() != SMDSAbs_Face )
4778       continue;
4779
4780     bool hasFreeLinks = false;
4781
4782     TIDSortedElemSet avoidSet;
4783     avoidSet.insert( elem );
4784
4785     set<const SMDS_MeshNode*> aFaceLastNodes;
4786     int iNode, nbNodes = vecNewNodes.size();
4787     if ( !isQuadratic ) {
4788       // loop on the face nodes
4789       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4790         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4791         // look for free links of the face
4792         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4793         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4794         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4795         // check if a link n1-n2 is free
4796         if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4797           hasFreeLinks = true;
4798           // make a new edge and a ceiling for a new edge
4799           const SMDS_MeshElement* edge;
4800           if ( ! ( edge = aMesh->FindEdge( n1, n2 ))) {
4801             myLastCreatedElems.Append( edge = aMesh->AddEdge( n1, n2 )); // free link edge
4802             srcElements.Append( myLastCreatedElems.Last() );
4803           }
4804           n1 = vecNewNodes[ iNode ]->second.back();
4805           n2 = vecNewNodes[ iNext ]->second.back();
4806           if ( !aMesh->FindEdge( n1, n2 )) {
4807             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling
4808             srcElements.Append( edge );
4809           }
4810         }
4811       }
4812     }
4813     else { // elem is quadratic face
4814       int nbn = nbNodes/2;
4815       for ( iNode = 0; iNode < nbn; iNode++ ) {
4816         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4817         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4818         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4819         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4820         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4821         // check if a link is free
4822         if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4823              ! SMESH_MeshAlgos::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4824              ! SMESH_MeshAlgos::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4825           hasFreeLinks = true;
4826           // make an edge and a ceiling for a new edge
4827           // find medium node
4828           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4829             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4830             srcElements.Append( elem );
4831           }
4832           n1 = vecNewNodes[ iNode ]->second.back();
4833           n2 = vecNewNodes[ iNext ]->second.back();
4834           n3 = vecNewNodes[ iNode+nbn ]->second.back();
4835           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4836             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4837             srcElements.Append( elem );
4838           }
4839         }
4840       }
4841       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4842         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4843       }
4844     }
4845
4846     // sweep free links into faces
4847
4848     if ( hasFreeLinks )  {
4849       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4850       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4851
4852       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4853       set<const SMDS_MeshNode*> initNodeSetNoCenter/*, topNodeSetNoCenter*/;
4854       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4855         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4856         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4857       }
4858       if ( isQuadratic && nbNodes % 2 ) {  // node set for the case of a biquadratic
4859         initNodeSetNoCenter = initNodeSet; // swept face and a not biquadratic volume
4860         initNodeSetNoCenter.erase( vecNewNodes.back()->first );
4861       }
4862       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4863         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4864         std::advance( v, volNb );
4865         // find indices of free faces of a volume and their source edges
4866         list< int > freeInd;
4867         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4868         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4869         int iF, nbF = vTool.NbFaces();
4870         for ( iF = 0; iF < nbF; iF ++ ) {
4871           if (vTool.IsFreeFace( iF ) &&
4872               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4873               initNodeSet != faceNodeSet) // except an initial face
4874           {
4875             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4876               continue;
4877             if ( faceNodeSet == initNodeSetNoCenter )
4878               continue;
4879             freeInd.push_back( iF );
4880             // find source edge of a free face iF
4881             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4882             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4883             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4884                                    initNodeSet.begin(), initNodeSet.end(),
4885                                    commonNodes.begin());
4886             if ( (*v)->IsQuadratic() )
4887               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4888             else
4889               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4890 #ifdef _DEBUG_
4891             if ( !srcEdges.back() )
4892             {
4893               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4894                    << iF << " of volume #" << vTool.ID() << endl;
4895             }
4896 #endif
4897           }
4898         }
4899         if ( freeInd.empty() )
4900           continue;
4901
4902         // create faces for all steps;
4903         // if such a face has been already created by sweep of edge,
4904         // assure that its orientation is OK
4905         for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4906           vTool.Set( *v, /*ignoreCentralNodes=*/false );
4907           vTool.SetExternalNormal();
4908           const int nextShift = vTool.IsForward() ? +1 : -1;
4909           list< int >::iterator ind = freeInd.begin();
4910           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4911           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4912           {
4913             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4914             int nbn = vTool.NbFaceNodes( *ind );
4915             const SMDS_MeshElement * f = 0;
4916             if ( nbn == 3 )              ///// triangle
4917             {
4918               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4919               if ( !f ||
4920                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4921               {
4922                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4923                                                      nodes[ 1 ],
4924                                                      nodes[ 1 + nextShift ] };
4925                 if ( f )
4926                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4927                 else
4928                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4929                                                             newOrder[ 2 ] ));
4930               }
4931             }
4932             else if ( nbn == 4 )       ///// quadrangle
4933             {
4934               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4935               if ( !f ||
4936                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4937               {
4938                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4939                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
4940                 if ( f )
4941                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4942                 else
4943                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4944                                                             newOrder[ 2 ], newOrder[ 3 ]));
4945               }
4946             }
4947             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4948             {
4949               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4950               if ( !f ||
4951                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4952               {
4953                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4954                                                      nodes[2],
4955                                                      nodes[2 + 2*nextShift],
4956                                                      nodes[3 - 2*nextShift],
4957                                                      nodes[3],
4958                                                      nodes[3 + 2*nextShift]};
4959                 if ( f )
4960                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4961                 else
4962                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4963                                                             newOrder[ 1 ],
4964                                                             newOrder[ 2 ],
4965                                                             newOrder[ 3 ],
4966                                                             newOrder[ 4 ],
4967                                                             newOrder[ 5 ] ));
4968               }
4969             }
4970             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4971             {
4972               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4973                                    nodes[1], nodes[3], nodes[5], nodes[7] );
4974               if ( !f ||
4975                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4976               {
4977                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4978                                                      nodes[4 - 2*nextShift],
4979                                                      nodes[4],
4980                                                      nodes[4 + 2*nextShift],
4981                                                      nodes[1],
4982                                                      nodes[5 - 2*nextShift],
4983                                                      nodes[5],
4984                                                      nodes[5 + 2*nextShift] };
4985                 if ( f )
4986                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4987                 else
4988                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4989                                                            newOrder[ 2 ], newOrder[ 3 ],
4990                                                            newOrder[ 4 ], newOrder[ 5 ],
4991                                                            newOrder[ 6 ], newOrder[ 7 ]));
4992               }
4993             }
4994             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4995             {
4996               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4997                                       SMDSAbs_Face, /*noMedium=*/false);
4998               if ( !f ||
4999                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
5000               {
5001                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
5002                                                      nodes[4 - 2*nextShift],
5003                                                      nodes[4],
5004                                                      nodes[4 + 2*nextShift],
5005                                                      nodes[1],
5006                                                      nodes[5 - 2*nextShift],
5007                                                      nodes[5],
5008                                                      nodes[5 + 2*nextShift],
5009                                                      nodes[8] };
5010                 if ( f )
5011                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
5012                 else
5013                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
5014                                                            newOrder[ 2 ], newOrder[ 3 ],
5015                                                            newOrder[ 4 ], newOrder[ 5 ],
5016                                                            newOrder[ 6 ], newOrder[ 7 ],
5017                                                            newOrder[ 8 ]));
5018               }
5019             }
5020             else  //////// polygon
5021             {
5022               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
5023               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
5024               if ( !f ||
5025                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
5026               {
5027                 if ( !vTool.IsForward() )
5028                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
5029                 if ( f )
5030                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
5031                 else
5032                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
5033               }
5034             }
5035
5036             while ( srcElements.Length() < myLastCreatedElems.Length() )
5037               srcElements.Append( *srcEdge );
5038
5039           }  // loop on free faces
5040
5041           // go to the next volume
5042           iVol = 0;
5043           while ( iVol++ < nbVolumesByStep ) v++;
5044
5045         } // loop on steps
5046       } // loop on volumes of one step
5047     } // sweep free links into faces
5048
5049     // Make a ceiling face with a normal external to a volume
5050
5051     // use SMDS_VolumeTool to get a correctly ordered nodes of a ceiling face
5052     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
5053     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
5054
5055     if ( iF < 0 && isQuadratic && nbNodes % 2 ) { // remove a central node of biquadratic
5056       aFaceLastNodes.erase( vecNewNodes.back()->second.back() );
5057       iF = lastVol.GetFaceIndex( aFaceLastNodes );
5058     }
5059     if ( iF >= 0 ) {
5060       lastVol.SetExternalNormal();
5061       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
5062       int nbn = lastVol.NbFaceNodes( iF );
5063       // we do not use this->AddElement() because nodes are interlaced
5064       vector<const SMDS_MeshNode*> nodeVec( nodes, nodes+nbn );
5065       if ( !hasFreeLinks ||
5066            !aMesh->FindElement( nodeVec, SMDSAbs_Face, /*noMedium=*/false) )
5067       {
5068         if ( nbn == 3 )
5069           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2] ));
5070
5071         else if ( nbn == 4 )
5072           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2], nodes[3]));
5073
5074         else if ( nbn == 6 && isQuadratic )
5075           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4],
5076                                                     nodes[1], nodes[3], nodes[5]));
5077         else if ( nbn == 7 && isQuadratic )
5078           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4],
5079                                                     nodes[1], nodes[3], nodes[5], nodes[6]));
5080         else if ( nbn == 8 && isQuadratic )
5081           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], nodes[6],
5082                                                     nodes[1], nodes[3], nodes[5], nodes[7]));
5083         else if ( nbn == 9 && isQuadratic )
5084           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], nodes[6],
5085                                                     nodes[1], nodes[3], nodes[5], nodes[7],
5086                                                     nodes[8]));
5087         else
5088           myLastCreatedElems.Append(aMesh->AddPolygonalFace( nodeVec ));
5089
5090         while ( srcElements.Length() < myLastCreatedElems.Length() )
5091           srcElements.Append( elem );
5092       }
5093     }
5094   } // loop on swept elements
5095 }
5096
5097 //=======================================================================
5098 //function : RotationSweep
5099 //purpose  :
5100 //=======================================================================
5101
5102 SMESH_MeshEditor::PGroupIDs
5103 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
5104                                 const gp_Ax1&      theAxis,
5105                                 const double       theAngle,
5106                                 const int          theNbSteps,
5107                                 const double       theTol,
5108                                 const bool         theMakeGroups,
5109                                 const bool         theMakeWalls)
5110 {
5111   myLastCreatedElems.Clear();
5112   myLastCreatedNodes.Clear();
5113
5114   // source elements for each generated one
5115   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5116
5117   MESSAGE( "RotationSweep()");
5118   gp_Trsf aTrsf;
5119   aTrsf.SetRotation( theAxis, theAngle );
5120   gp_Trsf aTrsf2;
5121   aTrsf2.SetRotation( theAxis, theAngle/2. );
5122
5123   gp_Lin aLine( theAxis );
5124   double aSqTol = theTol * theTol;
5125
5126   SMESHDS_Mesh* aMesh = GetMeshDS();
5127
5128   TNodeOfNodeListMap mapNewNodes;
5129   TElemOfVecOfNnlmiMap mapElemNewNodes;
5130   TTElemOfElemListMap newElemsMap;
5131
5132   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
5133                                      myMesh->NbFaces(ORDER_QUADRATIC) +
5134                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
5135   // loop on theElems
5136   TIDSortedElemSet::iterator itElem;
5137   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5138     const SMDS_MeshElement* elem = *itElem;
5139     if ( !elem || elem->GetType() == SMDSAbs_Volume )
5140       continue;
5141     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5142     newNodesItVec.reserve( elem->NbNodes() );
5143
5144     // loop on elem nodes
5145     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5146     while ( itN->more() )
5147     {
5148       // check if a node has been already sweeped
5149       const SMDS_MeshNode* node = cast2Node( itN->next() );
5150
5151       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
5152       double coord[3];
5153       aXYZ.Coord( coord[0], coord[1], coord[2] );
5154       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
5155
5156       TNodeOfNodeListMapItr nIt =
5157         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5158       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5159       if ( listNewNodes.empty() )
5160       {
5161         // check if we are to create medium nodes between corner ones
5162         bool needMediumNodes = false;
5163         if ( isQuadraticMesh )
5164         {
5165           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
5166           while (it->more() && !needMediumNodes )
5167           {
5168             const SMDS_MeshElement* invElem = it->next();
5169             if ( invElem != elem && !theElems.count( invElem )) continue;
5170             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
5171             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
5172               needMediumNodes = true;
5173           }
5174         }
5175
5176         // make new nodes
5177         const SMDS_MeshNode * newNode = node;
5178         for ( int i = 0; i < theNbSteps; i++ ) {
5179           if ( !isOnAxis ) {
5180             if ( needMediumNodes )  // create a medium node
5181             {
5182               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
5183               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5184               myLastCreatedNodes.Append(newNode);
5185               srcNodes.Append( node );
5186               listNewNodes.push_back( newNode );
5187               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
5188             }
5189             else {
5190               aTrsf.Transforms( coord[0], coord[1], coord[2] );
5191             }
5192             // create a corner node
5193             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5194             myLastCreatedNodes.Append(newNode);
5195             srcNodes.Append( node );
5196             listNewNodes.push_back( newNode );
5197           }
5198           else {
5199             listNewNodes.push_back( newNode );
5200             // if ( needMediumNodes )
5201             //   listNewNodes.push_back( newNode );
5202           }
5203         }
5204       }
5205       newNodesItVec.push_back( nIt );
5206     }
5207     // make new elements
5208     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
5209   }
5210
5211   if ( theMakeWalls )
5212     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
5213
5214   PGroupIDs newGroupIDs;
5215   if ( theMakeGroups )
5216     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
5217
5218   return newGroupIDs;
5219 }
5220
5221
5222 //=======================================================================
5223 //function : CreateNode
5224 //purpose  :
5225 //=======================================================================
5226 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
5227                                                   const double y,
5228                                                   const double z,
5229                                                   const double tolnode,
5230                                                   SMESH_SequenceOfNode& aNodes)
5231 {
5232   // myLastCreatedElems.Clear();
5233   // myLastCreatedNodes.Clear();
5234
5235   gp_Pnt P1(x,y,z);
5236   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
5237
5238   // try to search in sequence of existing nodes
5239   // if aNodes.Length()>0 we 'nave to use given sequence
5240   // else - use all nodes of mesh
5241   if(aNodes.Length()>0) {
5242     int i;
5243     for(i=1; i<=aNodes.Length(); i++) {
5244       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
5245       if(P1.Distance(P2)<tolnode)
5246         return aNodes.Value(i);
5247     }
5248   }
5249   else {
5250     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
5251     while(itn->more()) {
5252       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
5253       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
5254       if(P1.Distance(P2)<tolnode)
5255         return aN;
5256     }
5257   }
5258
5259   // create new node and return it
5260   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
5261   //myLastCreatedNodes.Append(NewNode);
5262   return NewNode;
5263 }
5264
5265
5266 //=======================================================================
5267 //function : ExtrusionSweep
5268 //purpose  :
5269 //=======================================================================
5270
5271 SMESH_MeshEditor::PGroupIDs
5272 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &   theElems,
5273                                   const gp_Vec&        theStep,
5274                                   const int            theNbSteps,
5275                                   TTElemOfElemListMap& newElemsMap,
5276                                   const bool           theMakeGroups,
5277                                   const int            theFlags,
5278                                   const double         theTolerance)
5279 {
5280   ExtrusParam aParams;
5281   aParams.myDir = gp_Dir(theStep);
5282   aParams.myNodes.Clear();
5283   aParams.mySteps = new TColStd_HSequenceOfReal;
5284   int i;
5285   for(i=1; i<=theNbSteps; i++)
5286     aParams.mySteps->Append(theStep.Magnitude());
5287
5288   return
5289     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
5290 }
5291
5292
5293 //=======================================================================
5294 //function : ExtrusionSweep
5295 //purpose  :
5296 //=======================================================================
5297
5298 SMESH_MeshEditor::PGroupIDs
5299 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &   theElems,
5300                                   ExtrusParam&         theParams,
5301                                   TTElemOfElemListMap& newElemsMap,
5302                                   const bool           theMakeGroups,
5303                                   const int            theFlags,
5304                                   const double         theTolerance)
5305 {
5306   myLastCreatedElems.Clear();
5307   myLastCreatedNodes.Clear();
5308
5309   // source elements for each generated one
5310   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5311
5312   SMESHDS_Mesh* aMesh = GetMeshDS();
5313
5314   int nbsteps = theParams.mySteps->Length();
5315
5316   TNodeOfNodeListMap mapNewNodes;
5317   //TNodeOfNodeVecMap mapNewNodes;
5318   TElemOfVecOfNnlmiMap mapElemNewNodes;
5319   //TElemOfVecOfMapNodesMap mapElemNewNodes;
5320
5321   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
5322                                      myMesh->NbFaces(ORDER_QUADRATIC) +
5323                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
5324   // loop on theElems
5325   TIDSortedElemSet::iterator itElem;
5326   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5327     // check element type
5328     const SMDS_MeshElement* elem = *itElem;
5329     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
5330       continue;
5331
5332     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5333     newNodesItVec.reserve( elem->NbNodes() );
5334
5335     // loop on elem nodes
5336     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5337     while ( itN->more() )
5338     {
5339       // check if a node has been already sweeped
5340       const SMDS_MeshNode* node = cast2Node( itN->next() );
5341       TNodeOfNodeListMap::iterator nIt =
5342         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5343       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5344       if ( listNewNodes.empty() )
5345       {
5346         // make new nodes
5347
5348         // check if we are to create medium nodes between corner ones
5349         bool needMediumNodes = false;
5350         if ( isQuadraticMesh )
5351         {
5352           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
5353           while (it->more() && !needMediumNodes )
5354           {
5355             const SMDS_MeshElement* invElem = it->next();
5356             if ( invElem != elem && !theElems.count( invElem )) continue;
5357             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
5358             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
5359               needMediumNodes = true;
5360           }
5361         }
5362
5363         double coord[] = { node->X(), node->Y(), node->Z() };
5364         for ( int i = 0; i < nbsteps; i++ )
5365         {
5366           if ( needMediumNodes ) // create a medium node
5367           {
5368             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
5369             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
5370             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
5371             if( theFlags & EXTRUSION_FLAG_SEW ) {
5372               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
5373                                                          theTolerance, theParams.myNodes);
5374               listNewNodes.push_back( newNode );
5375             }
5376             else {
5377               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
5378               myLastCreatedNodes.Append(newNode);
5379               srcNodes.Append( node );
5380               listNewNodes.push_back( newNode );
5381             }
5382           }
5383           // create a corner node
5384           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
5385           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
5386           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
5387           if( theFlags & EXTRUSION_FLAG_SEW ) {
5388             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
5389                                                        theTolerance, theParams.myNodes);
5390             listNewNodes.push_back( newNode );
5391           }
5392           else {
5393             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5394             myLastCreatedNodes.Append(newNode);
5395             srcNodes.Append( node );
5396             listNewNodes.push_back( newNode );
5397           }
5398         }
5399       }
5400       newNodesItVec.push_back( nIt );
5401     }
5402     // make new elements
5403     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
5404   }
5405
5406   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
5407     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
5408   }
5409   PGroupIDs newGroupIDs;
5410   if ( theMakeGroups )
5411     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
5412
5413   return newGroupIDs;
5414 }
5415
5416 //=======================================================================
5417 //function : ExtrusionAlongTrack
5418 //purpose  :
5419 //=======================================================================
5420 SMESH_MeshEditor::Extrusion_Error
5421 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
5422                                        SMESH_subMesh*       theTrack,
5423                                        const SMDS_MeshNode* theN1,
5424                                        const bool           theHasAngles,
5425                                        list<double>&        theAngles,
5426                                        const bool           theLinearVariation,
5427                                        const bool           theHasRefPoint,
5428                                        const gp_Pnt&        theRefPoint,
5429                                        const bool           theMakeGroups)
5430 {
5431   MESSAGE("ExtrusionAlongTrack");
5432   myLastCreatedElems.Clear();
5433   myLastCreatedNodes.Clear();
5434
5435   int aNbE;
5436   std::list<double> aPrms;
5437   TIDSortedElemSet::iterator itElem;
5438
5439   gp_XYZ aGC;
5440   TopoDS_Edge aTrackEdge;
5441   TopoDS_Vertex aV1, aV2;
5442
5443   SMDS_ElemIteratorPtr aItE;
5444   SMDS_NodeIteratorPtr aItN;
5445   SMDSAbs_ElementType aTypeE;
5446
5447   TNodeOfNodeListMap mapNewNodes;
5448
5449   // 1. Check data
5450   aNbE = theElements.size();
5451   // nothing to do
5452   if ( !aNbE )
5453     return EXTR_NO_ELEMENTS;
5454
5455   // 1.1 Track Pattern
5456   ASSERT( theTrack );
5457
5458   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
5459
5460   aItE = pSubMeshDS->GetElements();
5461   while ( aItE->more() ) {
5462     const SMDS_MeshElement* pE = aItE->next();
5463     aTypeE = pE->GetType();
5464     // Pattern must contain links only
5465     if ( aTypeE != SMDSAbs_Edge )
5466       return EXTR_PATH_NOT_EDGE;
5467   }
5468
5469   list<SMESH_MeshEditor_PathPoint> fullList;
5470
5471   const TopoDS_Shape& aS = theTrack->GetSubShape();
5472   // Sub-shape for the Pattern must be an Edge or Wire
5473   if( aS.ShapeType() == TopAbs_EDGE ) {
5474     aTrackEdge = TopoDS::Edge( aS );
5475     // the Edge must not be degenerated
5476     if ( SMESH_Algo::isDegenerated( aTrackEdge ) )
5477       return EXTR_BAD_PATH_SHAPE;
5478     TopExp::Vertices( aTrackEdge, aV1, aV2 );
5479     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
5480     const SMDS_MeshNode* aN1 = aItN->next();
5481     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
5482     const SMDS_MeshNode* aN2 = aItN->next();
5483     // starting node must be aN1 or aN2
5484     if ( !( aN1 == theN1 || aN2 == theN1 ) )
5485       return EXTR_BAD_STARTING_NODE;
5486     aItN = pSubMeshDS->GetNodes();
5487     while ( aItN->more() ) {
5488       const SMDS_MeshNode* pNode = aItN->next();
5489       const SMDS_EdgePosition* pEPos =
5490         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5491       double aT = pEPos->GetUParameter();
5492       aPrms.push_back( aT );
5493     }
5494     //Extrusion_Error err =
5495     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5496   } else if( aS.ShapeType() == TopAbs_WIRE ) {
5497     list< SMESH_subMesh* > LSM;
5498     TopTools_SequenceOfShape Edges;
5499     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
5500     while(itSM->more()) {
5501       SMESH_subMesh* SM = itSM->next();
5502       LSM.push_back(SM);
5503       const TopoDS_Shape& aS = SM->GetSubShape();
5504       Edges.Append(aS);
5505     }
5506     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5507     int startNid = theN1->GetID();
5508     TColStd_MapOfInteger UsedNums;
5509
5510     int NbEdges = Edges.Length();
5511     int i = 1;
5512     for(; i<=NbEdges; i++) {
5513       int k = 0;
5514       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5515       for(; itLSM!=LSM.end(); itLSM++) {
5516         k++;
5517         if(UsedNums.Contains(k)) continue;
5518         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5519         SMESH_subMesh* locTrack = *itLSM;
5520         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5521         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5522         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5523         const SMDS_MeshNode* aN1 = aItN->next();
5524         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5525         const SMDS_MeshNode* aN2 = aItN->next();
5526         // starting node must be aN1 or aN2
5527         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
5528         // 2. Collect parameters on the track edge
5529         aPrms.clear();
5530         aItN = locMeshDS->GetNodes();
5531         while ( aItN->more() ) {
5532           const SMDS_MeshNode* pNode = aItN->next();
5533           const SMDS_EdgePosition* pEPos =
5534             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5535           double aT = pEPos->GetUParameter();
5536           aPrms.push_back( aT );
5537         }
5538         list<SMESH_MeshEditor_PathPoint> LPP;
5539         //Extrusion_Error err =
5540         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
5541         LLPPs.push_back(LPP);
5542         UsedNums.Add(k);
5543         // update startN for search following egde
5544         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
5545         else startNid = aN1->GetID();
5546         break;
5547       }
5548     }
5549     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5550     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5551     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5552     for(; itPP!=firstList.end(); itPP++) {
5553       fullList.push_back( *itPP );
5554     }
5555     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5556     fullList.pop_back();
5557     itLLPP++;
5558     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5559       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5560       itPP = currList.begin();
5561       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5562       gp_Dir D1 = PP1.Tangent();
5563       gp_Dir D2 = PP2.Tangent();
5564       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5565                            (D1.Z()+D2.Z())/2 ) );
5566       PP1.SetTangent(Dnew);
5567       fullList.push_back(PP1);
5568       itPP++;
5569       for(; itPP!=firstList.end(); itPP++) {
5570         fullList.push_back( *itPP );
5571       }
5572       PP1 = fullList.back();
5573       fullList.pop_back();
5574     }
5575     // if wire not closed
5576     fullList.push_back(PP1);
5577     // else ???
5578   }
5579   else {
5580     return EXTR_BAD_PATH_SHAPE;
5581   }
5582
5583   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5584                           theHasRefPoint, theRefPoint, theMakeGroups);
5585 }
5586
5587
5588 //=======================================================================
5589 //function : ExtrusionAlongTrack
5590 //purpose  :
5591 //=======================================================================
5592 SMESH_MeshEditor::Extrusion_Error
5593 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
5594                                        SMESH_Mesh*          theTrack,
5595                                        const SMDS_MeshNode* theN1,
5596                                        const bool           theHasAngles,
5597                                        list<double>&        theAngles,
5598                                        const bool           theLinearVariation,
5599                                        const bool           theHasRefPoint,
5600                                        const gp_Pnt&        theRefPoint,
5601                                        const bool           theMakeGroups)
5602 {
5603   myLastCreatedElems.Clear();
5604   myLastCreatedNodes.Clear();
5605
5606   int aNbE;
5607   std::list<double> aPrms;
5608   TIDSortedElemSet::iterator itElem;
5609
5610   gp_XYZ aGC;
5611   TopoDS_Edge aTrackEdge;
5612   TopoDS_Vertex aV1, aV2;
5613
5614   SMDS_ElemIteratorPtr aItE;
5615   SMDS_NodeIteratorPtr aItN;
5616   SMDSAbs_ElementType aTypeE;
5617
5618   TNodeOfNodeListMap mapNewNodes;
5619
5620   // 1. Check data
5621   aNbE = theElements.size();
5622   // nothing to do
5623   if ( !aNbE )
5624     return EXTR_NO_ELEMENTS;
5625
5626   // 1.1 Track Pattern
5627   ASSERT( theTrack );
5628
5629   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
5630
5631   aItE = pMeshDS->elementsIterator();
5632   while ( aItE->more() ) {
5633     const SMDS_MeshElement* pE = aItE->next();
5634     aTypeE = pE->GetType();
5635     // Pattern must contain links only
5636     if ( aTypeE != SMDSAbs_Edge )
5637       return EXTR_PATH_NOT_EDGE;
5638   }
5639
5640   list<SMESH_MeshEditor_PathPoint> fullList;
5641
5642   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
5643
5644   if ( !theTrack->HasShapeToMesh() ) {
5645     //Mesh without shape
5646     const SMDS_MeshNode* currentNode = NULL;
5647     const SMDS_MeshNode* prevNode = theN1;
5648     std::vector<const SMDS_MeshNode*> aNodesList;
5649     aNodesList.push_back(theN1);
5650     int nbEdges = 0, conn=0;
5651     const SMDS_MeshElement* prevElem = NULL;
5652     const SMDS_MeshElement* currentElem = NULL;
5653     int totalNbEdges = theTrack->NbEdges();
5654     SMDS_ElemIteratorPtr nIt;
5655
5656     //check start node
5657     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
5658       return EXTR_BAD_STARTING_NODE;
5659     }
5660
5661     conn = nbEdgeConnectivity(theN1);
5662     if(conn > 2)
5663       return EXTR_PATH_NOT_EDGE;
5664
5665     aItE = theN1->GetInverseElementIterator();
5666     prevElem = aItE->next();
5667     currentElem = prevElem;
5668     //Get all nodes
5669     if(totalNbEdges == 1 ) {
5670       nIt = currentElem->nodesIterator();
5671       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5672       if(currentNode == prevNode)
5673         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5674       aNodesList.push_back(currentNode);
5675     } else {
5676       nIt = currentElem->nodesIterator();
5677       while( nIt->more() ) {
5678         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5679         if(currentNode == prevNode)
5680           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5681         aNodesList.push_back(currentNode);
5682
5683         //case of the closed mesh
5684         if(currentNode == theN1) {
5685           nbEdges++;
5686           break;
5687         }
5688
5689         conn = nbEdgeConnectivity(currentNode);
5690         if(conn > 2) {
5691           return EXTR_PATH_NOT_EDGE;
5692         }else if( conn == 1 && nbEdges > 0 ) {
5693           //End of the path
5694           nbEdges++;
5695           break;
5696         }else {
5697           prevNode = currentNode;
5698           aItE = currentNode->GetInverseElementIterator();
5699           currentElem = aItE->next();
5700           if( currentElem  == prevElem)
5701             currentElem = aItE->next();
5702           nIt = currentElem->nodesIterator();
5703           prevElem = currentElem;
5704           nbEdges++;
5705         }
5706       }
5707     }
5708
5709     if(nbEdges != totalNbEdges)
5710       return EXTR_PATH_NOT_EDGE;
5711
5712     TopTools_SequenceOfShape Edges;
5713     double x1,x2,y1,y2,z1,z2;
5714     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5715     int startNid = theN1->GetID();
5716     for(int i = 1; i < aNodesList.size(); i++) {
5717       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
5718       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
5719       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
5720       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));
5721       list<SMESH_MeshEditor_PathPoint> LPP;
5722       aPrms.clear();
5723       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
5724       LLPPs.push_back(LPP);
5725       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
5726       else startNid = aNodesList[i-1]->GetID();
5727
5728     }
5729
5730     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5731     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5732     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5733     for(; itPP!=firstList.end(); itPP++) {
5734       fullList.push_back( *itPP );
5735     }
5736
5737     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5738     SMESH_MeshEditor_PathPoint PP2;
5739     fullList.pop_back();
5740     itLLPP++;
5741     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5742       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5743       itPP = currList.begin();
5744       PP2 = currList.front();
5745       gp_Dir D1 = PP1.Tangent();
5746       gp_Dir D2 = PP2.Tangent();
5747       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5748                            (D1.Z()+D2.Z())/2 ) );
5749       PP1.SetTangent(Dnew);
5750       fullList.push_back(PP1);
5751       itPP++;
5752       for(; itPP!=currList.end(); itPP++) {
5753         fullList.push_back( *itPP );
5754       }
5755       PP1 = fullList.back();
5756       fullList.pop_back();
5757     }
5758     fullList.push_back(PP1);
5759
5760   } // Sub-shape for the Pattern must be an Edge or Wire
5761   else if( aS.ShapeType() == TopAbs_EDGE ) {
5762     aTrackEdge = TopoDS::Edge( aS );
5763     // the Edge must not be degenerated
5764     if ( SMESH_Algo::isDegenerated( aTrackEdge ) )
5765       return EXTR_BAD_PATH_SHAPE;
5766     TopExp::Vertices( aTrackEdge, aV1, aV2 );
5767     const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS );
5768     const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS );
5769     // starting node must be aN1 or aN2
5770     if ( !( aN1 == theN1 || aN2 == theN1 ) )
5771       return EXTR_BAD_STARTING_NODE;
5772     aItN = pMeshDS->nodesIterator();
5773     while ( aItN->more() ) {
5774       const SMDS_MeshNode* pNode = aItN->next();
5775       if( pNode==aN1 || pNode==aN2 ) continue;
5776       const SMDS_EdgePosition* pEPos =
5777         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5778       double aT = pEPos->GetUParameter();
5779       aPrms.push_back( aT );
5780     }
5781     //Extrusion_Error err =
5782     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5783   }
5784   else if( aS.ShapeType() == TopAbs_WIRE ) {
5785     list< SMESH_subMesh* > LSM;
5786     TopTools_SequenceOfShape Edges;
5787     TopExp_Explorer eExp(aS, TopAbs_EDGE);
5788     for(; eExp.More(); eExp.Next()) {
5789       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5790       if( SMESH_Algo::isDegenerated(E) ) continue;
5791       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5792       if(SM) {
5793         LSM.push_back(SM);
5794         Edges.Append(E);
5795       }
5796     }
5797     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5798     TopoDS_Vertex aVprev;
5799     TColStd_MapOfInteger UsedNums;
5800     int NbEdges = Edges.Length();
5801     int i = 1;
5802     for(; i<=NbEdges; i++) {
5803       int k = 0;
5804       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5805       for(; itLSM!=LSM.end(); itLSM++) {
5806         k++;
5807         if(UsedNums.Contains(k)) continue;
5808         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5809         SMESH_subMesh* locTrack = *itLSM;
5810         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5811         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5812         bool aN1isOK = false, aN2isOK = false;
5813         if ( aVprev.IsNull() ) {
5814           // if previous vertex is not yet defined, it means that we in the beginning of wire
5815           // and we have to find initial vertex corresponding to starting node theN1
5816           const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS );
5817           const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS );
5818           // starting node must be aN1 or aN2
5819           aN1isOK = ( aN1 && aN1 == theN1 );
5820           aN2isOK = ( aN2 && aN2 == theN1 );
5821         }
5822         else {
5823           // we have specified ending vertex of the previous edge on the previous iteration
5824           // and we have just to check that it corresponds to any vertex in current segment
5825           aN1isOK = aVprev.IsSame( aV1 );
5826           aN2isOK = aVprev.IsSame( aV2 );
5827         }
5828         if ( !aN1isOK && !aN2isOK ) continue;
5829         // 2. Collect parameters on the track edge
5830         aPrms.clear();
5831         aItN = locMeshDS->GetNodes();
5832         while ( aItN->more() ) {
5833           const SMDS_MeshNode*     pNode = aItN->next();
5834           const SMDS_EdgePosition* pEPos =
5835             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5836           double aT = pEPos->GetUParameter();
5837           aPrms.push_back( aT );
5838         }
5839         list<SMESH_MeshEditor_PathPoint> LPP;
5840         //Extrusion_Error err =
5841         MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
5842         LLPPs.push_back(LPP);
5843         UsedNums.Add(k);
5844         // update startN for search following egde
5845         if ( aN1isOK ) aVprev = aV2;
5846         else           aVprev = aV1;
5847         break;
5848       }
5849     }
5850     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5851     list<SMESH_MeshEditor_PathPoint>& firstList = *itLLPP;
5852     fullList.splice( fullList.end(), firstList );
5853
5854     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5855     fullList.pop_back();
5856     itLLPP++;
5857     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5858       list<SMESH_MeshEditor_PathPoint>& currList = *itLLPP;
5859       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5860       gp_Dir D1 = PP1.Tangent();
5861       gp_Dir D2 = PP2.Tangent();
5862       gp_Dir Dnew( ( D1.XYZ() + D2.XYZ() ) / 2 );
5863       PP1.SetTangent(Dnew);
5864       fullList.push_back(PP1);
5865       fullList.splice( fullList.end(), currList, ++currList.begin(), currList.end() );
5866       PP1 = fullList.back();
5867       fullList.pop_back();
5868     }
5869     // if wire not closed
5870     fullList.push_back(PP1);
5871     // else ???
5872   }
5873   else {
5874     return EXTR_BAD_PATH_SHAPE;
5875   }
5876
5877   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5878                           theHasRefPoint, theRefPoint, theMakeGroups);
5879 }
5880
5881
5882 //=======================================================================
5883 //function : MakeEdgePathPoints
5884 //purpose  : auxilary for ExtrusionAlongTrack
5885 //=======================================================================
5886 SMESH_MeshEditor::Extrusion_Error
5887 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>&                aPrms,
5888                                      const TopoDS_Edge&                aTrackEdge,
5889                                      bool                              FirstIsStart,
5890                                      list<SMESH_MeshEditor_PathPoint>& LPP)
5891 {
5892   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5893   aTolVec=1.e-7;
5894   aTolVec2=aTolVec*aTolVec;
5895   double aT1, aT2;
5896   TopoDS_Vertex aV1, aV2;
5897   TopExp::Vertices( aTrackEdge, aV1, aV2 );
5898   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5899   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5900   // 2. Collect parameters on the track edge
5901   aPrms.push_front( aT1 );
5902   aPrms.push_back( aT2 );
5903   // sort parameters
5904   aPrms.sort();
5905   if( FirstIsStart ) {
5906     if ( aT1 > aT2 ) {
5907       aPrms.reverse();
5908     }
5909   }
5910   else {
5911     if ( aT2 > aT1 ) {
5912       aPrms.reverse();
5913     }
5914   }
5915   // 3. Path Points
5916   SMESH_MeshEditor_PathPoint aPP;
5917   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5918   std::list<double>::iterator aItD = aPrms.begin();
5919   for(; aItD != aPrms.end(); ++aItD) {
5920     double aT = *aItD;
5921     gp_Pnt aP3D;
5922     gp_Vec aVec;
5923     aC3D->D1( aT, aP3D, aVec );
5924     aL2 = aVec.SquareMagnitude();
5925     if ( aL2 < aTolVec2 )
5926       return EXTR_CANT_GET_TANGENT;
5927     gp_Dir aTgt( aVec );
5928     aPP.SetPnt( aP3D );
5929     aPP.SetTangent( aTgt );
5930     aPP.SetParameter( aT );
5931     LPP.push_back(aPP);
5932   }
5933   return EXTR_OK;
5934 }
5935
5936
5937 //=======================================================================
5938 //function : MakeExtrElements
5939 //purpose  : auxilary for ExtrusionAlongTrack
5940 //=======================================================================
5941 SMESH_MeshEditor::Extrusion_Error
5942 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&                 theElements,
5943                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5944                                    const bool                        theHasAngles,
5945                                    list<double>&                     theAngles,
5946                                    const bool                        theLinearVariation,
5947                                    const bool                        theHasRefPoint,
5948                                    const gp_Pnt&                     theRefPoint,
5949                                    const bool                        theMakeGroups)
5950 {
5951   const int aNbTP = fullList.size();
5952   // Angles
5953   if( theHasAngles && !theAngles.empty() && theLinearVariation )
5954     LinearAngleVariation(aNbTP-1, theAngles);
5955   // fill vector of path points with angles
5956   vector<SMESH_MeshEditor_PathPoint> aPPs;
5957   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5958   list<double>::iterator                 itAngles = theAngles.begin();
5959   aPPs.push_back( *itPP++ );
5960   for( ; itPP != fullList.end(); itPP++) {
5961     aPPs.push_back( *itPP );
5962     if ( theHasAngles && itAngles != theAngles.end() )
5963       aPPs.back().SetAngle( *itAngles++ );
5964   }
5965
5966   TNodeOfNodeListMap   mapNewNodes;
5967   TElemOfVecOfNnlmiMap mapElemNewNodes;
5968   TTElemOfElemListMap  newElemsMap;
5969   TIDSortedElemSet::iterator itElem;
5970   // source elements for each generated one
5971   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5972
5973   // 3. Center of rotation aV0
5974   gp_Pnt aV0 = theRefPoint;
5975   if ( !theHasRefPoint )
5976   {
5977     gp_XYZ aGC( 0.,0.,0. );
5978     TIDSortedElemSet newNodes;
5979
5980     itElem = theElements.begin();
5981     for ( ; itElem != theElements.end(); itElem++ ) {
5982       const SMDS_MeshElement* elem = *itElem;
5983
5984       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5985       while ( itN->more() ) {
5986         const SMDS_MeshElement* node = itN->next();
5987         if ( newNodes.insert( node ).second )
5988           aGC += SMESH_TNodeXYZ( node );
5989       }
5990     }
5991     aGC /= newNodes.size();
5992     aV0.SetXYZ( aGC );
5993   } // if (!theHasRefPoint) {
5994
5995   // 4. Processing the elements
5996   SMESHDS_Mesh* aMesh = GetMeshDS();
5997
5998   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5999     // check element type
6000     const SMDS_MeshElement* elem = *itElem;
6001     SMDSAbs_ElementType   aTypeE = elem->GetType();
6002     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
6003       continue;
6004
6005     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
6006     newNodesItVec.reserve( elem->NbNodes() );
6007
6008     // loop on elem nodes
6009     int nodeIndex = -1;
6010     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6011     while ( itN->more() )
6012     {
6013       ++nodeIndex;
6014       // check if a node has been already processed
6015       const SMDS_MeshNode* node =
6016         static_cast<const SMDS_MeshNode*>( itN->next() );
6017       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
6018       if ( nIt == mapNewNodes.end() ) {
6019         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
6020         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
6021
6022         // make new nodes
6023         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
6024         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
6025         gp_Ax1 anAx1, anAxT1T0;
6026         gp_Dir aDT1x, aDT0x, aDT1T0;
6027
6028         aTolAng=1.e-4;
6029
6030         aV0x = aV0;
6031         aPN0 = SMESH_TNodeXYZ( node );
6032
6033         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
6034         aP0x = aPP0.Pnt();
6035         aDT0x= aPP0.Tangent();
6036         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
6037
6038         for ( int j = 1; j < aNbTP; ++j ) {
6039           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
6040           aP1x     = aPP1.Pnt();
6041           aDT1x    = aPP1.Tangent();
6042           aAngle1x = aPP1.Angle();
6043
6044           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
6045           // Translation
6046           gp_Vec aV01x( aP0x, aP1x );
6047           aTrsf.SetTranslation( aV01x );
6048
6049           // traslated point
6050           aV1x = aV0x.Transformed( aTrsf );
6051           aPN1 = aPN0.Transformed( aTrsf );
6052
6053           // rotation 1 [ T1,T0 ]
6054           aAngleT1T0=-aDT1x.Angle( aDT0x );
6055           if (fabs(aAngleT1T0) > aTolAng) {
6056             aDT1T0=aDT1x^aDT0x;
6057             anAxT1T0.SetLocation( aV1x );
6058             anAxT1T0.SetDirection( aDT1T0 );
6059             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
6060
6061             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
6062           }
6063
6064           // rotation 2
6065           if ( theHasAngles ) {
6066             anAx1.SetLocation( aV1x );
6067             anAx1.SetDirection( aDT1x );
6068             aTrsfRot.SetRotation( anAx1, aAngle1x );
6069
6070             aPN1 = aPN1.Transformed( aTrsfRot );
6071           }
6072
6073           // make new node
6074           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
6075           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
6076             // create additional node
6077             double x = ( aPN1.X() + aPN0.X() )/2.;
6078             double y = ( aPN1.Y() + aPN0.Y() )/2.;
6079             double z = ( aPN1.Z() + aPN0.Z() )/2.;
6080             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
6081             myLastCreatedNodes.Append(newNode);
6082             srcNodes.Append( node );
6083             listNewNodes.push_back( newNode );
6084           }
6085           const SMDS_MeshNode* newNode = aMesh->AddNode( aPN1.X(), aPN1.Y(), aPN1.Z() );
6086           myLastCreatedNodes.Append(newNode);
6087           srcNodes.Append( node );
6088           listNewNodes.push_back( newNode );
6089
6090           aPN0 = aPN1;
6091           aP0x = aP1x;
6092           aV0x = aV1x;
6093           aDT0x = aDT1x;
6094         }
6095       }
6096
6097       else {
6098         // if current elem is quadratic and current node is not medium
6099         // we have to check - may be it is needed to insert additional nodes
6100         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
6101           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
6102           if(listNewNodes.size()==aNbTP-1) {
6103             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
6104             gp_XYZ P(node->X(), node->Y(), node->Z());
6105             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
6106             int i;
6107             for(i=0; i<aNbTP-1; i++) {
6108               const SMDS_MeshNode* N = *it;
6109               double x = ( N->X() + P.X() )/2.;
6110               double y = ( N->Y() + P.Y() )/2.;
6111               double z = ( N->Z() + P.Z() )/2.;
6112               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
6113               srcNodes.Append( node );
6114               myLastCreatedNodes.Append(newN);
6115               aNodes[2*i] = newN;
6116               aNodes[2*i+1] = N;
6117               P = gp_XYZ(N->X(),N->Y(),N->Z());
6118             }
6119             listNewNodes.clear();
6120             for(i=0; i<2*(aNbTP-1); i++) {
6121               listNewNodes.push_back(aNodes[i]);
6122             }
6123           }
6124         }
6125       }
6126
6127       newNodesItVec.push_back( nIt );
6128     }
6129     // make new elements
6130     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
6131     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
6132     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
6133   }
6134
6135   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
6136
6137   if ( theMakeGroups )
6138     generateGroups( srcNodes, srcElems, "extruded");
6139
6140   return EXTR_OK;
6141 }
6142
6143
6144 //=======================================================================
6145 //function : LinearAngleVariation
6146 //purpose  : auxilary for ExtrusionAlongTrack
6147 //=======================================================================
6148 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
6149                                             list<double>& Angles)
6150 {
6151   int nbAngles = Angles.size();
6152   if( nbSteps > nbAngles ) {
6153     vector<double> theAngles(nbAngles);
6154     list<double>::iterator it = Angles.begin();
6155     int i = -1;
6156     for(; it!=Angles.end(); it++) {
6157       i++;
6158       theAngles[i] = (*it);
6159     }
6160     list<double> res;
6161     double rAn2St = double( nbAngles ) / double( nbSteps );
6162     double angPrev = 0, angle;
6163     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
6164       double angCur = rAn2St * ( iSt+1 );
6165       double angCurFloor  = floor( angCur );
6166       double angPrevFloor = floor( angPrev );
6167       if ( angPrevFloor == angCurFloor )
6168         angle = rAn2St * theAngles[ int( angCurFloor ) ];
6169       else {
6170         int iP = int( angPrevFloor );
6171         double angPrevCeil = ceil(angPrev);
6172         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
6173
6174         int iC = int( angCurFloor );
6175         if ( iC < nbAngles )
6176           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
6177
6178         iP = int( angPrevCeil );
6179         while ( iC-- > iP )
6180           angle += theAngles[ iC ];
6181       }
6182       res.push_back(angle);
6183       angPrev = angCur;
6184     }
6185     Angles.clear();
6186     it = res.begin();
6187     for(; it!=res.end(); it++)
6188       Angles.push_back( *it );
6189   }
6190 }
6191
6192
6193 //================================================================================
6194 /*!
6195  * \brief Move or copy theElements applying theTrsf to their nodes
6196  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
6197  *  \param theTrsf - transformation to apply
6198  *  \param theCopy - if true, create translated copies of theElems
6199  *  \param theMakeGroups - if true and theCopy, create translated groups
6200  *  \param theTargetMesh - mesh to copy translated elements into
6201  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
6202  */
6203 //================================================================================
6204
6205 SMESH_MeshEditor::PGroupIDs
6206 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
6207                              const gp_Trsf&     theTrsf,
6208                              const bool         theCopy,
6209                              const bool         theMakeGroups,
6210                              SMESH_Mesh*        theTargetMesh)
6211 {
6212   myLastCreatedElems.Clear();
6213   myLastCreatedNodes.Clear();
6214
6215   bool needReverse = false;
6216   string groupPostfix;
6217   switch ( theTrsf.Form() ) {
6218   case gp_PntMirror:
6219     MESSAGE("gp_PntMirror");
6220     needReverse = true;
6221     groupPostfix = "mirrored";
6222     break;
6223   case gp_Ax1Mirror:
6224     MESSAGE("gp_Ax1Mirror");
6225     groupPostfix = "mirrored";
6226     break;
6227   case gp_Ax2Mirror:
6228     MESSAGE("gp_Ax2Mirror");
6229     needReverse = true;
6230     groupPostfix = "mirrored";
6231     break;
6232   case gp_Rotation:
6233     MESSAGE("gp_Rotation");
6234     groupPostfix = "rotated";
6235     break;
6236   case gp_Translation:
6237     MESSAGE("gp_Translation");
6238     groupPostfix = "translated";
6239     break;
6240   case gp_Scale:
6241     MESSAGE("gp_Scale");
6242     groupPostfix = "scaled";
6243     break;
6244   case gp_CompoundTrsf: // different scale by axis
6245     MESSAGE("gp_CompoundTrsf");
6246     groupPostfix = "scaled";
6247     break;
6248   default:
6249     MESSAGE("default");
6250     needReverse = false;
6251     groupPostfix = "transformed";
6252   }
6253
6254   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
6255   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
6256   SMESHDS_Mesh* aMesh    = GetMeshDS();
6257
6258
6259   // map old node to new one
6260   TNodeNodeMap nodeMap;
6261
6262   // elements sharing moved nodes; those of them which have all
6263   // nodes mirrored but are not in theElems are to be reversed
6264   TIDSortedElemSet inverseElemSet;
6265
6266   // source elements for each generated one
6267   SMESH_SequenceOfElemPtr srcElems, srcNodes;
6268
6269   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
6270   TIDSortedElemSet orphanNode;
6271
6272   if ( theElems.empty() ) // transform the whole mesh
6273   {
6274     // add all elements
6275     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
6276     while ( eIt->more() ) theElems.insert( eIt->next() );
6277     // add orphan nodes
6278     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
6279     while ( nIt->more() )
6280     {
6281       const SMDS_MeshNode* node = nIt->next();
6282       if ( node->NbInverseElements() == 0)
6283         orphanNode.insert( node );
6284     }
6285   }
6286
6287   // loop on elements to transform nodes : first orphan nodes then elems
6288   TIDSortedElemSet::iterator itElem;
6289   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
6290   for (int i=0; i<2; i++)
6291   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
6292     const SMDS_MeshElement* elem = *itElem;
6293     if ( !elem )
6294       continue;
6295
6296     // loop on elem nodes
6297     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6298     while ( itN->more() ) {
6299
6300       const SMDS_MeshNode* node = cast2Node( itN->next() );
6301       // check if a node has been already transformed
6302       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
6303         nodeMap.insert( make_pair ( node, node ));
6304       if ( !n2n_isnew.second )
6305         continue;
6306
6307       double coord[3];
6308       coord[0] = node->X();
6309       coord[1] = node->Y();
6310       coord[2] = node->Z();
6311       theTrsf.Transforms( coord[0], coord[1], coord[2] );
6312       if ( theTargetMesh ) {
6313         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
6314         n2n_isnew.first->second = newNode;
6315         myLastCreatedNodes.Append(newNode);
6316         srcNodes.Append( node );
6317       }
6318       else if ( theCopy ) {
6319         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
6320         n2n_isnew.first->second = newNode;
6321         myLastCreatedNodes.Append(newNode);
6322         srcNodes.Append( node );
6323       }
6324       else {
6325         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
6326         // node position on shape becomes invalid
6327         const_cast< SMDS_MeshNode* > ( node )->SetPosition
6328           ( SMDS_SpacePosition::originSpacePosition() );
6329       }
6330
6331       // keep inverse elements
6332       if ( !theCopy && !theTargetMesh && needReverse ) {
6333         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
6334         while ( invElemIt->more() ) {
6335           const SMDS_MeshElement* iel = invElemIt->next();
6336           inverseElemSet.insert( iel );
6337         }
6338       }
6339     }
6340   }
6341
6342   // either create new elements or reverse mirrored ones
6343   if ( !theCopy && !needReverse && !theTargetMesh )
6344     return PGroupIDs();
6345
6346   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
6347   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
6348     theElems.insert( *invElemIt );
6349
6350   // Replicate or reverse elements
6351
6352   std::vector<int> iForw;
6353   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
6354   {
6355     const SMDS_MeshElement* elem = *itElem;
6356     if ( !elem ) continue;
6357
6358     SMDSAbs_GeometryType geomType = elem->GetGeomType();
6359     int                  nbNodes  = elem->NbNodes();
6360     if ( geomType == SMDSGeom_NONE ) continue; // node
6361
6362     switch ( geomType ) {
6363
6364     case SMDSGeom_POLYGON:  // ---------------------- polygon
6365       {
6366         vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
6367         int iNode = 0;
6368         SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6369         while (itN->more()) {
6370           const SMDS_MeshNode* node =
6371             static_cast<const SMDS_MeshNode*>(itN->next());
6372           TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
6373           if (nodeMapIt == nodeMap.end())
6374             break; // not all nodes transformed
6375           if (needReverse) {
6376             // reverse mirrored faces and volumes
6377             poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
6378           } else {
6379             poly_nodes[iNode] = (*nodeMapIt).second;
6380           }
6381           iNode++;
6382         }
6383         if ( iNode != nbNodes )
6384           continue; // not all nodes transformed
6385
6386         if ( theTargetMesh ) {
6387           myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
6388           srcElems.Append( elem );
6389         }
6390         else if ( theCopy ) {
6391           myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
6392           srcElems.Append( elem );
6393         }
6394         else {
6395           aMesh->ChangePolygonNodes(elem, poly_nodes);
6396         }
6397       }
6398       break;
6399
6400     case SMDSGeom_POLYHEDRA:  // ------------------ polyhedral volume
6401       {
6402         const SMDS_VtkVolume* aPolyedre =
6403           dynamic_cast<const SMDS_VtkVolume*>( elem );
6404         if (!aPolyedre) {
6405           MESSAGE("Warning: bad volumic element");
6406           continue;
6407         }
6408
6409         vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
6410         vector<int> quantities; quantities.reserve( nbNodes );
6411
6412         bool allTransformed = true;
6413         int nbFaces = aPolyedre->NbFaces();
6414         for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
6415           int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6416           for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
6417             const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
6418             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
6419             if (nodeMapIt == nodeMap.end()) {
6420               allTransformed = false; // not all nodes transformed
6421             } else {
6422               poly_nodes.push_back((*nodeMapIt).second);
6423             }
6424             if ( needReverse && allTransformed )
6425               std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
6426           }
6427           quantities.push_back(nbFaceNodes);
6428         }
6429         if ( !allTransformed )
6430           continue; // not all nodes transformed
6431
6432         if ( theTargetMesh ) {
6433           myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
6434           srcElems.Append( elem );
6435         }
6436         else if ( theCopy ) {
6437           myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
6438           srcElems.Append( elem );
6439         }
6440         else {
6441           aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6442         }
6443       }
6444       break;
6445
6446     case SMDSGeom_BALL: // -------------------- Ball
6447       {
6448         if ( !theCopy && !theTargetMesh ) continue;
6449
6450         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) );
6451         if (nodeMapIt == nodeMap.end())
6452           continue; // not all nodes transformed
6453
6454         double diameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
6455         if ( theTargetMesh ) {
6456           myLastCreatedElems.Append(aTgtMesh->AddBall( nodeMapIt->second, diameter ));
6457           srcElems.Append( elem );
6458         }
6459         else {
6460           myLastCreatedElems.Append(aMesh->AddBall( nodeMapIt->second, diameter ));
6461           srcElems.Append( elem );
6462         }
6463       }
6464       break;
6465
6466     default: // ----------------------- Regular elements
6467
6468       while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
6469       const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
6470       const std::vector<int>& i = needReverse ? iRev : iForw;
6471
6472       // find transformed nodes
6473       vector<const SMDS_MeshNode*> nodes(nbNodes);
6474       int iNode = 0;
6475       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6476       while ( itN->more() ) {
6477         const SMDS_MeshNode* node =
6478           static_cast<const SMDS_MeshNode*>( itN->next() );
6479         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
6480         if ( nodeMapIt == nodeMap.end() )
6481           break; // not all nodes transformed
6482         nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
6483       }
6484       if ( iNode != nbNodes )
6485         continue; // not all nodes transformed
6486
6487       if ( theTargetMesh ) {
6488         if ( SMDS_MeshElement* copy =
6489              targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
6490           myLastCreatedElems.Append( copy );
6491           srcElems.Append( elem );
6492         }
6493       }
6494       else if ( theCopy ) {
6495         if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
6496           srcElems.Append( elem );
6497       }
6498       else {
6499         // reverse element as it was reversed by transformation
6500         if ( nbNodes > 2 )
6501           aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
6502       }
6503     } // switch ( geomType )
6504
6505   } // loop on elements
6506
6507   PGroupIDs newGroupIDs;
6508
6509   if ( ( theMakeGroups && theCopy ) ||
6510        ( theMakeGroups && theTargetMesh ) )
6511     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh, false );
6512
6513   return newGroupIDs;
6514 }
6515
6516 //=======================================================================
6517 /*!
6518  * \brief Create groups of elements made during transformation
6519  *  \param nodeGens - nodes making corresponding myLastCreatedNodes
6520  *  \param elemGens - elements making corresponding myLastCreatedElems
6521  *  \param postfix - to append to names of new groups
6522  *  \param targetMesh - mesh to create groups in
6523  *  \param topPresent - is there "top" elements that are created by sweeping
6524  */
6525 //=======================================================================
6526
6527 SMESH_MeshEditor::PGroupIDs
6528 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
6529                                  const SMESH_SequenceOfElemPtr& elemGens,
6530                                  const std::string&             postfix,
6531                                  SMESH_Mesh*                    targetMesh,
6532                                  const bool                     topPresent)
6533 {
6534   PGroupIDs newGroupIDs( new list<int> );
6535   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6536
6537   // Sort existing groups by types and collect their names
6538
6539   // containers to store an old group and generated new ones;
6540   // 1st new group is for result elems of different type than a source one;
6541   // 2nd new group is for same type result elems ("top" group at extrusion)
6542   using boost::tuple;
6543   using boost::make_tuple;
6544   typedef tuple< SMESHDS_GroupBase*, SMESHDS_Group*, SMESHDS_Group* > TOldNewGroup;
6545   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6546   vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups
6547   // group names
6548   set< string > groupNames;
6549
6550   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6551   if ( !groupIt->more() ) return newGroupIDs;
6552
6553   int newGroupID = mesh->GetGroupIds().back()+1;
6554   while ( groupIt->more() )
6555   {
6556     SMESH_Group * group = groupIt->next();
6557     if ( !group ) continue;
6558     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6559     if ( !groupDS || groupDS->IsEmpty() ) continue;
6560     groupNames.insert    ( group->GetName() );
6561     groupDS->SetStoreName( group->GetName() );
6562     const SMDSAbs_ElementType type = groupDS->GetType();
6563     SMESHDS_Group* newGroup    = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
6564     SMESHDS_Group* newTopGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
6565     groupsByType[ type ].push_back( make_tuple( groupDS, newGroup, newTopGroup ));
6566     orderedOldNewGroups.push_back( & groupsByType[ type ].back() );
6567   }
6568
6569   // Loop on nodes and elements to add them in new groups
6570
6571   vector< const SMDS_MeshElement* > resultElems;
6572   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6573   {
6574     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6575     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6576     if ( gens.Length() != elems.Length() )
6577       throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args");
6578
6579     // loop on created elements
6580     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6581     {
6582       const SMDS_MeshElement* sourceElem = gens( iElem );
6583       if ( !sourceElem ) {
6584         MESSAGE("generateGroups(): NULL source element");
6585         continue;
6586       }
6587       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6588       if ( groupsOldNew.empty() ) { // no groups of this type at all
6589         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6590           ++iElem; // skip all elements made by sourceElem
6591         continue;
6592       }
6593       // collect all elements made by the iElem-th sourceElem
6594       resultElems.clear();
6595       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6596         if ( resElem != sourceElem )
6597           resultElems.push_back( resElem );
6598       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6599         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6600           if ( resElem != sourceElem )
6601             resultElems.push_back( resElem );
6602
6603       const SMDS_MeshElement* topElem = 0;
6604       if ( isNodes ) // there must be a top element
6605       {
6606         topElem = resultElems.back();
6607         resultElems.pop_back();
6608       }
6609       else
6610       {
6611         vector< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin();
6612         for ( ; resElemIt != resultElems.rend() ; ++resElemIt )
6613           if ( (*resElemIt)->GetType() == sourceElem->GetType() )
6614           {
6615             topElem = *resElemIt;
6616             *resElemIt = 0; // erase *resElemIt
6617             break;
6618           }
6619       }
6620       // add resultElems to groups originted from ones the sourceElem belongs to
6621       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6622       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6623       {
6624         SMESHDS_GroupBase* oldGroup = gOldNew->get<0>();
6625         if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup
6626         {
6627           // fill in a new group
6628           SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup();
6629           vector< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6630           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6631             if ( *resElemIt )
6632               newGroup.Add( *resElemIt );
6633
6634           // fill a "top" group
6635           if ( topElem )
6636           {
6637             SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup();
6638             newTopGroup.Add( topElem );
6639          }
6640         }
6641       }
6642     } // loop on created elements
6643   }// loop on nodes and elements
6644
6645   // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups
6646
6647   list<int> topGrouIds;
6648   for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i )
6649   {
6650     SMESHDS_GroupBase* oldGroupDS =   orderedOldNewGroups[i]->get<0>();
6651     SMESHDS_Group*   newGroups[2] = { orderedOldNewGroups[i]->get<1>(),
6652                                       orderedOldNewGroups[i]->get<2>() };
6653     for ( int is2nd = 0; is2nd < 2; ++is2nd )
6654     {
6655       SMESHDS_Group* newGroupDS = newGroups[ is2nd ];
6656       if ( newGroupDS->IsEmpty() )
6657       {
6658         mesh->GetMeshDS()->RemoveGroup( newGroupDS );
6659       }
6660       else
6661       {
6662         // set group type
6663         newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
6664
6665         // make a name
6666         const bool isTop = ( topPresent &&
6667                              newGroupDS->GetType() == oldGroupDS->GetType() &&
6668                              is2nd );
6669
6670         string name = oldGroupDS->GetStoreName();
6671         { // remove trailing whitespaces (issue 22599)
6672           size_t size = name.size();
6673           while ( size > 1 && isspace( name[ size-1 ]))
6674             --size;
6675           if ( size != name.size() )
6676           {
6677             name.resize( size );
6678             oldGroupDS->SetStoreName( name.c_str() );
6679           }
6680         }
6681         if ( !targetMesh ) {
6682           string suffix = ( isTop ? "top": postfix.c_str() );
6683           name += "_";
6684           name += suffix;
6685           int nb = 1;
6686           while ( !groupNames.insert( name ).second ) // name exists
6687             name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << suffix << "_" << nb++;
6688         }
6689         else if ( isTop ) {
6690           name += "_top";
6691         }
6692         newGroupDS->SetStoreName( name.c_str() );
6693
6694         // make a SMESH_Groups
6695         mesh->AddGroup( newGroupDS );
6696         if ( isTop )
6697           topGrouIds.push_back( newGroupDS->GetID() );
6698         else
6699           newGroupIDs->push_back( newGroupDS->GetID() );
6700       }
6701     }
6702   }
6703   newGroupIDs->splice( newGroupIDs->end(), topGrouIds );
6704
6705   return newGroupIDs;
6706 }
6707
6708 //================================================================================
6709 /*!
6710  * \brief Return list of group of nodes close to each other within theTolerance
6711  *        Search among theNodes or in the whole mesh if theNodes is empty using
6712  *        an Octree algorithm
6713  */
6714 //================================================================================
6715
6716 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6717                                             const double         theTolerance,
6718                                             TListOfListOfNodes & theGroupsOfNodes)
6719 {
6720   myLastCreatedElems.Clear();
6721   myLastCreatedNodes.Clear();
6722
6723   if ( theNodes.empty() )
6724   { // get all nodes in the mesh
6725     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6726     while ( nIt->more() )
6727       theNodes.insert( theNodes.end(),nIt->next());
6728   }
6729
6730   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6731 }
6732
6733 //=======================================================================
6734 //function : SimplifyFace
6735 //purpose  :
6736 //=======================================================================
6737
6738 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *>& faceNodes,
6739                                     vector<const SMDS_MeshNode *>&       poly_nodes,
6740                                     vector<int>&                         quantities) const
6741 {
6742   int nbNodes = faceNodes.size();
6743
6744   if (nbNodes < 3)
6745     return 0;
6746
6747   set<const SMDS_MeshNode*> nodeSet;
6748
6749   // get simple seq of nodes
6750   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6751   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6752   int iSimple = 0, nbUnique = 0;
6753
6754   simpleNodes[iSimple++] = faceNodes[0];
6755   nbUnique++;
6756   for (int iCur = 1; iCur < nbNodes; iCur++) {
6757     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6758       simpleNodes[iSimple++] = faceNodes[iCur];
6759       if (nodeSet.insert( faceNodes[iCur] ).second)
6760         nbUnique++;
6761     }
6762   }
6763   int nbSimple = iSimple;
6764   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6765     nbSimple--;
6766     iSimple--;
6767   }
6768
6769   if (nbUnique < 3)
6770     return 0;
6771
6772   // separate loops
6773   int nbNew = 0;
6774   bool foundLoop = (nbSimple > nbUnique);
6775   while (foundLoop) {
6776     foundLoop = false;
6777     set<const SMDS_MeshNode*> loopSet;
6778     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6779       const SMDS_MeshNode* n = simpleNodes[iSimple];
6780       if (!loopSet.insert( n ).second) {
6781         foundLoop = true;
6782
6783         // separate loop
6784         int iC = 0, curLast = iSimple;
6785         for (; iC < curLast; iC++) {
6786           if (simpleNodes[iC] == n) break;
6787         }
6788         int loopLen = curLast - iC;
6789         if (loopLen > 2) {
6790           // create sub-element
6791           nbNew++;
6792           quantities.push_back(loopLen);
6793           for (; iC < curLast; iC++) {
6794             poly_nodes.push_back(simpleNodes[iC]);
6795           }
6796         }
6797         // shift the rest nodes (place from the first loop position)
6798         for (iC = curLast + 1; iC < nbSimple; iC++) {
6799           simpleNodes[iC - loopLen] = simpleNodes[iC];
6800         }
6801         nbSimple -= loopLen;
6802         iSimple -= loopLen;
6803       }
6804     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6805   } // while (foundLoop)
6806
6807   if (iSimple > 2) {
6808     nbNew++;
6809     quantities.push_back(iSimple);
6810     for (int i = 0; i < iSimple; i++)
6811       poly_nodes.push_back(simpleNodes[i]);
6812   }
6813
6814   return nbNew;
6815 }
6816
6817 //=======================================================================
6818 //function : MergeNodes
6819 //purpose  : In each group, the cdr of nodes are substituted by the first one
6820 //           in all elements.
6821 //=======================================================================
6822
6823 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6824 {
6825   MESSAGE("MergeNodes");
6826   myLastCreatedElems.Clear();
6827   myLastCreatedNodes.Clear();
6828
6829   SMESHDS_Mesh* aMesh = GetMeshDS();
6830
6831   TNodeNodeMap nodeNodeMap; // node to replace - new node
6832   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6833   list< int > rmElemIds, rmNodeIds;
6834
6835   // Fill nodeNodeMap and elems
6836
6837   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6838   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6839     list<const SMDS_MeshNode*>& nodes = *grIt;
6840     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6841     const SMDS_MeshNode* nToKeep = *nIt;
6842     //MESSAGE("node to keep " << nToKeep->GetID());
6843     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6844       const SMDS_MeshNode* nToRemove = *nIt;
6845       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6846       if ( nToRemove != nToKeep ) {
6847         //MESSAGE("  node to remove " << nToRemove->GetID());
6848         rmNodeIds.push_back( nToRemove->GetID() );
6849         AddToSameGroups( nToKeep, nToRemove, aMesh );
6850         // set _alwaysComputed to a sub-mesh of VERTEX to enable mesh computing
6851         // after MergeNodes() w/o creating node in place of merged ones.
6852         const SMDS_PositionPtr& pos = nToRemove->GetPosition();
6853         if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX )
6854           if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() ))
6855             sm->SetIsAlwaysComputed( true );
6856       }
6857
6858       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6859       while ( invElemIt->more() ) {
6860         const SMDS_MeshElement* elem = invElemIt->next();
6861         elems.insert(elem);
6862       }
6863     }
6864   }
6865   // Change element nodes or remove an element
6866
6867   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6868   for ( ; eIt != elems.end(); eIt++ ) {
6869     const SMDS_MeshElement* elem = *eIt;
6870     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
6871     int nbNodes = elem->NbNodes();
6872     int aShapeId = FindShape( elem );
6873
6874     set<const SMDS_MeshNode*> nodeSet;
6875     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6876     int iUnique = 0, iCur = 0, nbRepl = 0;
6877     vector<int> iRepl( nbNodes );
6878
6879     // get new seq of nodes
6880     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6881     while ( itN->more() ) {
6882       const SMDS_MeshNode* n =
6883         static_cast<const SMDS_MeshNode*>( itN->next() );
6884
6885       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6886       if ( nnIt != nodeNodeMap.end() ) { // n sticks
6887         n = (*nnIt).second;
6888         // BUG 0020185: begin
6889         {
6890           bool stopRecur = false;
6891           set<const SMDS_MeshNode*> nodesRecur;
6892           nodesRecur.insert(n);
6893           while (!stopRecur) {
6894             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6895             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6896               n = (*nnIt_i).second;
6897               if (!nodesRecur.insert(n).second) {
6898                 // error: recursive dependancy
6899                 stopRecur = true;
6900               }
6901             }
6902             else
6903               stopRecur = true;
6904           }
6905         }
6906         // BUG 0020185: end
6907       }
6908       curNodes[ iCur ] = n;
6909       bool isUnique = nodeSet.insert( n ).second;
6910       if ( isUnique )
6911         uniqueNodes[ iUnique++ ] = n;
6912       else
6913         iRepl[ nbRepl++ ] = iCur;
6914       iCur++;
6915     }
6916
6917     // Analyse element topology after replacement
6918
6919     bool isOk = true;
6920     int nbUniqueNodes = nodeSet.size();
6921     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
6922     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6923       // Polygons and Polyhedral volumes
6924       if (elem->IsPoly()) {
6925
6926         if (elem->GetType() == SMDSAbs_Face) {
6927           // Polygon
6928           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6929           int inode = 0;
6930           for (; inode < nbNodes; inode++) {
6931             face_nodes[inode] = curNodes[inode];
6932           }
6933
6934           vector<const SMDS_MeshNode *> polygons_nodes;
6935           vector<int> quantities;
6936           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6937           if (nbNew > 0) {
6938             inode = 0;
6939             for (int iface = 0; iface < nbNew; iface++) {
6940               int nbNodes = quantities[iface];
6941               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6942               for (int ii = 0; ii < nbNodes; ii++, inode++) {
6943                 poly_nodes[ii] = polygons_nodes[inode];
6944               }
6945               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6946               myLastCreatedElems.Append(newElem);
6947               if (aShapeId)
6948                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6949             }
6950
6951             MESSAGE("ChangeElementNodes MergeNodes Polygon");
6952             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6953             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
6954             int quid =0;
6955             if (nbNew > 0) quid = nbNew - 1;
6956             vector<int> newquant(quantities.begin()+quid, quantities.end());
6957             const SMDS_MeshElement* newElem = 0;
6958             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
6959             myLastCreatedElems.Append(newElem);
6960             if ( aShapeId && newElem )
6961               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6962             rmElemIds.push_back(elem->GetID());
6963           }
6964           else {
6965             rmElemIds.push_back(elem->GetID());
6966           }
6967
6968         }
6969         else if (elem->GetType() == SMDSAbs_Volume) {
6970           // Polyhedral volume
6971           if (nbUniqueNodes < 4) {
6972             rmElemIds.push_back(elem->GetID());
6973           }
6974           else {
6975             // each face has to be analyzed in order to check volume validity
6976             const SMDS_VtkVolume* aPolyedre =
6977               dynamic_cast<const SMDS_VtkVolume*>( elem );
6978             if (aPolyedre) {
6979               int nbFaces = aPolyedre->NbFaces();
6980
6981               vector<const SMDS_MeshNode *> poly_nodes;
6982               vector<int> quantities;
6983
6984               for (int iface = 1; iface <= nbFaces; iface++) {
6985                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6986                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
6987
6988                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
6989                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
6990                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
6991                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
6992                     faceNode = (*nnIt).second;
6993                   }
6994                   faceNodes[inode - 1] = faceNode;
6995                 }
6996
6997                 SimplifyFace(faceNodes, poly_nodes, quantities);
6998               }
6999
7000               if (quantities.size() > 3) {
7001                 // to be done: remove coincident faces
7002               }
7003
7004               if (quantities.size() > 3)
7005                 {
7006                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7007                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7008                   const SMDS_MeshElement* newElem = 0;
7009                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7010                   myLastCreatedElems.Append(newElem);
7011                   if ( aShapeId && newElem )
7012                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7013                   rmElemIds.push_back(elem->GetID());
7014                 }
7015             }
7016             else {
7017               rmElemIds.push_back(elem->GetID());
7018             }
7019           }
7020         }
7021         else {
7022         }
7023
7024         continue;
7025       } // poly element
7026
7027       // Regular elements
7028       // TODO not all the possible cases are solved. Find something more generic?
7029       switch ( nbNodes ) {
7030       case 2: ///////////////////////////////////// EDGE
7031         isOk = false; break;
7032       case 3: ///////////////////////////////////// TRIANGLE
7033         isOk = false; break;
7034       case 4:
7035         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7036           isOk = false;
7037         else { //////////////////////////////////// QUADRANGLE
7038           if ( nbUniqueNodes < 3 )
7039             isOk = false;
7040           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7041             isOk = false; // opposite nodes stick
7042           //MESSAGE("isOk " << isOk);
7043         }
7044         break;
7045       case 6: ///////////////////////////////////// PENTAHEDRON
7046         if ( nbUniqueNodes == 4 ) {
7047           // ---------------------------------> tetrahedron
7048           if (nbRepl == 3 &&
7049               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7050             // all top nodes stick: reverse a bottom
7051             uniqueNodes[ 0 ] = curNodes [ 1 ];
7052             uniqueNodes[ 1 ] = curNodes [ 0 ];
7053           }
7054           else if (nbRepl == 3 &&
7055                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7056             // all bottom nodes stick: set a top before
7057             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7058             uniqueNodes[ 0 ] = curNodes [ 3 ];
7059             uniqueNodes[ 1 ] = curNodes [ 4 ];
7060             uniqueNodes[ 2 ] = curNodes [ 5 ];
7061           }
7062           else if (nbRepl == 4 &&
7063                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7064             // a lateral face turns into a line: reverse a bottom
7065             uniqueNodes[ 0 ] = curNodes [ 1 ];
7066             uniqueNodes[ 1 ] = curNodes [ 0 ];
7067           }
7068           else
7069             isOk = false;
7070         }
7071         else if ( nbUniqueNodes == 5 ) {
7072           // PENTAHEDRON --------------------> 2 tetrahedrons
7073           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7074             // a bottom node sticks with a linked top one
7075             // 1.
7076             SMDS_MeshElement* newElem =
7077               aMesh->AddVolume(curNodes[ 3 ],
7078                                curNodes[ 4 ],
7079                                curNodes[ 5 ],
7080                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7081             myLastCreatedElems.Append(newElem);
7082             if ( aShapeId )
7083               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7084             // 2. : reverse a bottom
7085             uniqueNodes[ 0 ] = curNodes [ 1 ];
7086             uniqueNodes[ 1 ] = curNodes [ 0 ];
7087             nbUniqueNodes = 4;
7088           }
7089           else
7090             isOk = false;
7091         }
7092         else
7093           isOk = false;
7094         break;
7095       case 8: {
7096         if(elem->IsQuadratic()) { // Quadratic quadrangle
7097           //   1    5    2
7098           //    +---+---+
7099           //    |       |
7100           //    |       |
7101           //   4+       +6
7102           //    |       |
7103           //    |       |
7104           //    +---+---+
7105           //   0    7    3
7106           isOk = false;
7107           if(nbRepl==2) {
7108             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7109           }
7110           if(nbRepl==3) {
7111             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7112             nbUniqueNodes = 6;
7113             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7114               uniqueNodes[0] = curNodes[0];
7115               uniqueNodes[1] = curNodes[2];
7116               uniqueNodes[2] = curNodes[3];
7117               uniqueNodes[3] = curNodes[5];
7118               uniqueNodes[4] = curNodes[6];
7119               uniqueNodes[5] = curNodes[7];
7120               isOk = true;
7121             }
7122             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7123               uniqueNodes[0] = curNodes[0];
7124               uniqueNodes[1] = curNodes[1];
7125               uniqueNodes[2] = curNodes[2];
7126               uniqueNodes[3] = curNodes[4];
7127               uniqueNodes[4] = curNodes[5];
7128               uniqueNodes[5] = curNodes[6];
7129               isOk = true;
7130             }
7131             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7132               uniqueNodes[0] = curNodes[1];
7133               uniqueNodes[1] = curNodes[2];
7134               uniqueNodes[2] = curNodes[3];
7135               uniqueNodes[3] = curNodes[5];
7136               uniqueNodes[4] = curNodes[6];
7137               uniqueNodes[5] = curNodes[0];
7138               isOk = true;
7139             }
7140             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7141               uniqueNodes[0] = curNodes[0];
7142               uniqueNodes[1] = curNodes[1];
7143               uniqueNodes[2] = curNodes[3];
7144               uniqueNodes[3] = curNodes[4];
7145               uniqueNodes[4] = curNodes[6];
7146               uniqueNodes[5] = curNodes[7];
7147               isOk = true;
7148             }
7149             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7150               uniqueNodes[0] = curNodes[0];
7151               uniqueNodes[1] = curNodes[2];
7152               uniqueNodes[2] = curNodes[3];
7153               uniqueNodes[3] = curNodes[1];
7154               uniqueNodes[4] = curNodes[6];
7155               uniqueNodes[5] = curNodes[7];
7156               isOk = true;
7157             }
7158             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7159               uniqueNodes[0] = curNodes[0];
7160               uniqueNodes[1] = curNodes[1];
7161               uniqueNodes[2] = curNodes[2];
7162               uniqueNodes[3] = curNodes[4];
7163               uniqueNodes[4] = curNodes[5];
7164               uniqueNodes[5] = curNodes[7];
7165               isOk = true;
7166             }
7167             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7168               uniqueNodes[0] = curNodes[0];
7169               uniqueNodes[1] = curNodes[1];
7170               uniqueNodes[2] = curNodes[3];
7171               uniqueNodes[3] = curNodes[4];
7172               uniqueNodes[4] = curNodes[2];
7173               uniqueNodes[5] = curNodes[7];
7174               isOk = true;
7175             }
7176             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7177               uniqueNodes[0] = curNodes[0];
7178               uniqueNodes[1] = curNodes[1];
7179               uniqueNodes[2] = curNodes[2];
7180               uniqueNodes[3] = curNodes[4];
7181               uniqueNodes[4] = curNodes[5];
7182               uniqueNodes[5] = curNodes[3];
7183               isOk = true;
7184             }
7185           }
7186           if(nbRepl==4) {
7187             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7188           }
7189           if(nbRepl==5) {
7190             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7191           }
7192           break;
7193         }
7194         //////////////////////////////////// HEXAHEDRON
7195         isOk = false;
7196         SMDS_VolumeTool hexa (elem);
7197         hexa.SetExternalNormal();
7198         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7199           //////////////////////// HEX ---> 1 tetrahedron
7200           for ( int iFace = 0; iFace < 6; iFace++ ) {
7201             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7202             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7203                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7204                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7205               // one face turns into a point ...
7206               int iOppFace = hexa.GetOppFaceIndex( iFace );
7207               ind = hexa.GetFaceNodesIndices( iOppFace );
7208               int nbStick = 0;
7209               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7210                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7211                   nbStick++;
7212               }
7213               if ( nbStick == 1 ) {
7214                 // ... and the opposite one - into a triangle.
7215                 // set a top node
7216                 ind = hexa.GetFaceNodesIndices( iFace );
7217                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7218                 isOk = true;
7219               }
7220               break;
7221             }
7222           }
7223         }
7224         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7225           //////////////////////// HEX ---> 1 prism
7226           int nbTria = 0, iTria[3];
7227           const int *ind; // indices of face nodes
7228           // look for triangular faces
7229           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7230             ind = hexa.GetFaceNodesIndices( iFace );
7231             TIDSortedNodeSet faceNodes;
7232             for ( iCur = 0; iCur < 4; iCur++ )
7233               faceNodes.insert( curNodes[ind[iCur]] );
7234             if ( faceNodes.size() == 3 )
7235               iTria[ nbTria++ ] = iFace;
7236           }
7237           // check if triangles are opposite
7238           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7239           {
7240             isOk = true;
7241             // set nodes of the bottom triangle
7242             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7243             vector<int> indB;
7244             for ( iCur = 0; iCur < 4; iCur++ )
7245               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7246                 indB.push_back( ind[iCur] );
7247             if ( !hexa.IsForward() )
7248               std::swap( indB[0], indB[2] );
7249             for ( iCur = 0; iCur < 3; iCur++ )
7250               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7251             // set nodes of the top triangle
7252             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7253             for ( iCur = 0; iCur < 3; ++iCur )
7254               for ( int j = 0; j < 4; ++j )
7255                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7256                 {
7257                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7258                   break;
7259                 }
7260           }
7261           break;
7262         }
7263         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7264           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7265           for ( int iFace = 0; iFace < 6; iFace++ ) {
7266             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7267             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7268                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7269                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7270               // one face turns into a point ...
7271               int iOppFace = hexa.GetOppFaceIndex( iFace );
7272               ind = hexa.GetFaceNodesIndices( iOppFace );
7273               int nbStick = 0;
7274               iUnique = 2;  // reverse a tetrahedron 1 bottom
7275               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7276                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7277                   nbStick++;
7278                 else if ( iUnique >= 0 )
7279                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7280               }
7281               if ( nbStick == 0 ) {
7282                 // ... and the opposite one is a quadrangle
7283                 // set a top node
7284                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7285                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7286                 nbUniqueNodes = 4;
7287                 // tetrahedron 2
7288                 SMDS_MeshElement* newElem =
7289                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7290                                    curNodes[ind[ 3 ]],
7291                                    curNodes[ind[ 2 ]],
7292                                    curNodes[indTop[ 0 ]]);
7293                 myLastCreatedElems.Append(newElem);
7294                 if ( aShapeId )
7295                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7296                 isOk = true;
7297               }
7298               break;
7299             }
7300           }
7301         }
7302         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7303           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7304           // find indices of quad and tri faces
7305           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7306           for ( iFace = 0; iFace < 6; iFace++ ) {
7307             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7308             nodeSet.clear();
7309             for ( iCur = 0; iCur < 4; iCur++ )
7310               nodeSet.insert( curNodes[ind[ iCur ]] );
7311             nbUniqueNodes = nodeSet.size();
7312             if ( nbUniqueNodes == 3 )
7313               iTriFace[ nbTri++ ] = iFace;
7314             else if ( nbUniqueNodes == 4 )
7315               iQuadFace[ nbQuad++ ] = iFace;
7316           }
7317           if (nbQuad == 2 && nbTri == 4 &&
7318               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7319             // 2 opposite quadrangles stuck with a diagonal;
7320             // sample groups of merged indices: (0-4)(2-6)
7321             // --------------------------------------------> 2 tetrahedrons
7322             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7323             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7324             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7325             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7326                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7327               // stuck with 0-2 diagonal
7328               i0  = ind1[ 3 ];
7329               i1d = ind1[ 0 ];
7330               i2  = ind1[ 1 ];
7331               i3d = ind1[ 2 ];
7332               i0t = ind2[ 1 ];
7333               i2t = ind2[ 3 ];
7334             }
7335             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7336                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7337               // stuck with 1-3 diagonal
7338               i0  = ind1[ 0 ];
7339               i1d = ind1[ 1 ];
7340               i2  = ind1[ 2 ];
7341               i3d = ind1[ 3 ];
7342               i0t = ind2[ 0 ];
7343               i2t = ind2[ 1 ];
7344             }
7345             else {
7346               ASSERT(0);
7347             }
7348             // tetrahedron 1
7349             uniqueNodes[ 0 ] = curNodes [ i0 ];
7350             uniqueNodes[ 1 ] = curNodes [ i1d ];
7351             uniqueNodes[ 2 ] = curNodes [ i3d ];
7352             uniqueNodes[ 3 ] = curNodes [ i0t ];
7353             nbUniqueNodes = 4;
7354             // tetrahedron 2
7355             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7356                                                          curNodes[ i2 ],
7357                                                          curNodes[ i3d ],
7358                                                          curNodes[ i2t ]);
7359             myLastCreatedElems.Append(newElem);
7360             if ( aShapeId )
7361               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7362             isOk = true;
7363           }
7364           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7365                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7366             // --------------------------------------------> prism
7367             // find 2 opposite triangles
7368             nbUniqueNodes = 6;
7369             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7370               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7371                 // find indices of kept and replaced nodes
7372                 // and fill unique nodes of 2 opposite triangles
7373                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7374                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7375                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7376                 // fill unique nodes
7377                 iUnique = 0;
7378                 isOk = true;
7379                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7380                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7381                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7382                   if ( n == nInit ) {
7383                     // iCur of a linked node of the opposite face (make normals co-directed):
7384                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7385                     // check that correspondent corners of triangles are linked
7386                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7387                       isOk = false;
7388                     else {
7389                       uniqueNodes[ iUnique ] = n;
7390                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7391                       iUnique++;
7392                     }
7393                   }
7394                 }
7395                 break;
7396               }
7397             }
7398           }
7399         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7400         else
7401         {
7402           MESSAGE("MergeNodes() removes hexahedron "<< elem);
7403         }
7404         break;
7405       } // HEXAHEDRON
7406
7407       default:
7408         isOk = false;
7409       } // switch ( nbNodes )
7410
7411     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7412
7413     if ( isOk ) { // the elem remains valid after sticking nodes
7414       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
7415       {
7416         // Change nodes of polyedre
7417         const SMDS_VtkVolume* aPolyedre =
7418           dynamic_cast<const SMDS_VtkVolume*>( elem );
7419         if (aPolyedre) {
7420           int nbFaces = aPolyedre->NbFaces();
7421
7422           vector<const SMDS_MeshNode *> poly_nodes;
7423           vector<int> quantities (nbFaces);
7424
7425           for (int iface = 1; iface <= nbFaces; iface++) {
7426             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7427             quantities[iface - 1] = nbFaceNodes;
7428
7429             for (inode = 1; inode <= nbFaceNodes; inode++) {
7430               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7431
7432               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7433               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7434                 curNode = (*nnIt).second;
7435               }
7436               poly_nodes.push_back(curNode);
7437             }
7438           }
7439           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7440         }
7441       }
7442       else // replace non-polyhedron elements
7443       {
7444         const SMDSAbs_ElementType etyp = elem->GetType();
7445         const int elemId               = elem->GetID();
7446         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
7447         uniqueNodes.resize(nbUniqueNodes);
7448
7449         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
7450
7451         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7452         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
7453         if ( sm && newElem )
7454           sm->AddElement( newElem );
7455         if ( elem != newElem )
7456           ReplaceElemInGroups( elem, newElem, aMesh );
7457       }
7458     }
7459     else {
7460       // Remove invalid regular element or invalid polygon
7461       rmElemIds.push_back( elem->GetID() );
7462     }
7463
7464   } // loop on elements
7465
7466   // Remove bad elements, then equal nodes (order important)
7467
7468   Remove( rmElemIds, false );
7469   Remove( rmNodeIds, true );
7470
7471 }
7472
7473
7474 // ========================================================
7475 // class   : SortableElement
7476 // purpose : allow sorting elements basing on their nodes
7477 // ========================================================
7478 class SortableElement : public set <const SMDS_MeshElement*>
7479 {
7480 public:
7481
7482   SortableElement( const SMDS_MeshElement* theElem )
7483   {
7484     myElem = theElem;
7485     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7486     while ( nodeIt->more() )
7487       this->insert( nodeIt->next() );
7488   }
7489
7490   const SMDS_MeshElement* Get() const
7491   { return myElem; }
7492
7493   void Set(const SMDS_MeshElement* e) const
7494   { myElem = e; }
7495
7496
7497 private:
7498   mutable const SMDS_MeshElement* myElem;
7499 };
7500
7501 //=======================================================================
7502 //function : FindEqualElements
7503 //purpose  : Return list of group of elements built on the same nodes.
7504 //           Search among theElements or in the whole mesh if theElements is empty
7505 //=======================================================================
7506
7507 void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet &        theElements,
7508                                          TListOfListOfElementsID & theGroupsOfElementsID)
7509 {
7510   myLastCreatedElems.Clear();
7511   myLastCreatedNodes.Clear();
7512
7513   typedef map< SortableElement, int > TMapOfNodeSet;
7514   typedef list<int> TGroupOfElems;
7515
7516   if ( theElements.empty() )
7517   { // get all elements in the mesh
7518     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7519     while ( eIt->more() )
7520       theElements.insert( theElements.end(), eIt->next());
7521   }
7522
7523   vector< TGroupOfElems > arrayOfGroups;
7524   TGroupOfElems groupOfElems;
7525   TMapOfNodeSet mapOfNodeSet;
7526
7527   TIDSortedElemSet::iterator elemIt = theElements.begin();
7528   for ( int i = 0, j=0; elemIt != theElements.end(); ++elemIt, ++j ) {
7529     const SMDS_MeshElement* curElem = *elemIt;
7530     SortableElement SE(curElem);
7531     int ind = -1;
7532     // check uniqueness
7533     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7534     if( !(pp.second) ) {
7535       TMapOfNodeSet::iterator& itSE = pp.first;
7536       ind = (*itSE).second;
7537       arrayOfGroups[ind].push_back(curElem->GetID());
7538     }
7539     else {
7540       groupOfElems.clear();
7541       groupOfElems.push_back(curElem->GetID());
7542       arrayOfGroups.push_back(groupOfElems);
7543       i++;
7544     }
7545   }
7546
7547   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7548   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7549     groupOfElems = *groupIt;
7550     if ( groupOfElems.size() > 1 ) {
7551       groupOfElems.sort();
7552       theGroupsOfElementsID.push_back(groupOfElems);
7553     }
7554   }
7555 }
7556
7557 //=======================================================================
7558 //function : MergeElements
7559 //purpose  : In each given group, substitute all elements by the first one.
7560 //=======================================================================
7561
7562 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7563 {
7564   myLastCreatedElems.Clear();
7565   myLastCreatedNodes.Clear();
7566
7567   typedef list<int> TListOfIDs;
7568   TListOfIDs rmElemIds; // IDs of elems to remove
7569
7570   SMESHDS_Mesh* aMesh = GetMeshDS();
7571
7572   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7573   while ( groupsIt != theGroupsOfElementsID.end() ) {
7574     TListOfIDs& aGroupOfElemID = *groupsIt;
7575     aGroupOfElemID.sort();
7576     int elemIDToKeep = aGroupOfElemID.front();
7577     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7578     aGroupOfElemID.pop_front();
7579     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7580     while ( idIt != aGroupOfElemID.end() ) {
7581       int elemIDToRemove = *idIt;
7582       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7583       // add the kept element in groups of removed one (PAL15188)
7584       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7585       rmElemIds.push_back( elemIDToRemove );
7586       ++idIt;
7587     }
7588     ++groupsIt;
7589   }
7590
7591   Remove( rmElemIds, false );
7592 }
7593
7594 //=======================================================================
7595 //function : MergeEqualElements
7596 //purpose  : Remove all but one of elements built on the same nodes.
7597 //=======================================================================
7598
7599 void SMESH_MeshEditor::MergeEqualElements()
7600 {
7601   TIDSortedElemSet aMeshElements; /* empty input ==
7602                                      to merge equal elements in the whole mesh */
7603   TListOfListOfElementsID aGroupsOfElementsID;
7604   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7605   MergeElements(aGroupsOfElementsID);
7606 }
7607
7608 //=======================================================================
7609 //function : findAdjacentFace
7610 //purpose  :
7611 //=======================================================================
7612
7613 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7614                                                 const SMDS_MeshNode* n2,
7615                                                 const SMDS_MeshElement* elem)
7616 {
7617   TIDSortedElemSet elemSet, avoidSet;
7618   if ( elem )
7619     avoidSet.insert ( elem );
7620   return SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet );
7621 }
7622
7623 //=======================================================================
7624 //function : FindFreeBorder
7625 //purpose  :
7626 //=======================================================================
7627
7628 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7629
7630 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7631                                        const SMDS_MeshNode*             theSecondNode,
7632                                        const SMDS_MeshNode*             theLastNode,
7633                                        list< const SMDS_MeshNode* > &   theNodes,
7634                                        list< const SMDS_MeshElement* >& theFaces)
7635 {
7636   if ( !theFirstNode || !theSecondNode )
7637     return false;
7638   // find border face between theFirstNode and theSecondNode
7639   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7640   if ( !curElem )
7641     return false;
7642
7643   theFaces.push_back( curElem );
7644   theNodes.push_back( theFirstNode );
7645   theNodes.push_back( theSecondNode );
7646
7647   //vector<const SMDS_MeshNode*> nodes;
7648   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7649   TIDSortedElemSet foundElems;
7650   bool needTheLast = ( theLastNode != 0 );
7651
7652   while ( nStart != theLastNode ) {
7653     if ( nStart == theFirstNode )
7654       return !needTheLast;
7655
7656     // find all free border faces sharing form nStart
7657
7658     list< const SMDS_MeshElement* > curElemList;
7659     list< const SMDS_MeshNode* > nStartList;
7660     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7661     while ( invElemIt->more() ) {
7662       const SMDS_MeshElement* e = invElemIt->next();
7663       if ( e == curElem || foundElems.insert( e ).second ) {
7664         // get nodes
7665         int iNode = 0, nbNodes = e->NbNodes();
7666         //const SMDS_MeshNode* nodes[nbNodes+1];
7667         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7668
7669         if(e->IsQuadratic()) {
7670           const SMDS_VtkFace* F =
7671             dynamic_cast<const SMDS_VtkFace*>(e);
7672           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7673           // use special nodes iterator
7674           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7675           while( anIter->more() ) {
7676             nodes[ iNode++ ] = cast2Node(anIter->next());
7677           }
7678         }
7679         else {
7680           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7681           while ( nIt->more() )
7682             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7683         }
7684         nodes[ iNode ] = nodes[ 0 ];
7685         // check 2 links
7686         for ( iNode = 0; iNode < nbNodes; iNode++ )
7687           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7688                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7689               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7690           {
7691             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7692             curElemList.push_back( e );
7693           }
7694       }
7695     }
7696     // analyse the found
7697
7698     int nbNewBorders = curElemList.size();
7699     if ( nbNewBorders == 0 ) {
7700       // no free border furthermore
7701       return !needTheLast;
7702     }
7703     else if ( nbNewBorders == 1 ) {
7704       // one more element found
7705       nIgnore = nStart;
7706       nStart = nStartList.front();
7707       curElem = curElemList.front();
7708       theFaces.push_back( curElem );
7709       theNodes.push_back( nStart );
7710     }
7711     else {
7712       // several continuations found
7713       list< const SMDS_MeshElement* >::iterator curElemIt;
7714       list< const SMDS_MeshNode* >::iterator nStartIt;
7715       // check if one of them reached the last node
7716       if ( needTheLast ) {
7717         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7718              curElemIt!= curElemList.end();
7719              curElemIt++, nStartIt++ )
7720           if ( *nStartIt == theLastNode ) {
7721             theFaces.push_back( *curElemIt );
7722             theNodes.push_back( *nStartIt );
7723             return true;
7724           }
7725       }
7726       // find the best free border by the continuations
7727       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7728       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7729       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7730            curElemIt!= curElemList.end();
7731            curElemIt++, nStartIt++ )
7732       {
7733         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7734         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7735         // find one more free border
7736         if ( ! SMESH_MeshEditor::FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7737           cNL->clear();
7738           cFL->clear();
7739         }
7740         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7741           // choice: clear a worse one
7742           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7743           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7744           contNodes[ iWorse ].clear();
7745           contFaces[ iWorse ].clear();
7746         }
7747       }
7748       if ( contNodes[0].empty() && contNodes[1].empty() )
7749         return false;
7750
7751       // append the best free border
7752       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7753       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7754       theNodes.pop_back(); // remove nIgnore
7755       theNodes.pop_back(); // remove nStart
7756       theFaces.pop_back(); // remove curElem
7757       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7758       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7759       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7760       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7761       return true;
7762
7763     } // several continuations found
7764   } // while ( nStart != theLastNode )
7765
7766   return true;
7767 }
7768
7769 //=======================================================================
7770 //function : CheckFreeBorderNodes
7771 //purpose  : Return true if the tree nodes are on a free border
7772 //=======================================================================
7773
7774 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7775                                             const SMDS_MeshNode* theNode2,
7776                                             const SMDS_MeshNode* theNode3)
7777 {
7778   list< const SMDS_MeshNode* > nodes;
7779   list< const SMDS_MeshElement* > faces;
7780   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7781 }
7782
7783 //=======================================================================
7784 //function : SewFreeBorder
7785 //purpose  :
7786 //=======================================================================
7787
7788 SMESH_MeshEditor::Sew_Error
7789 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7790                                  const SMDS_MeshNode* theBordSecondNode,
7791                                  const SMDS_MeshNode* theBordLastNode,
7792                                  const SMDS_MeshNode* theSideFirstNode,
7793                                  const SMDS_MeshNode* theSideSecondNode,
7794                                  const SMDS_MeshNode* theSideThirdNode,
7795                                  const bool           theSideIsFreeBorder,
7796                                  const bool           toCreatePolygons,
7797                                  const bool           toCreatePolyedrs)
7798 {
7799   myLastCreatedElems.Clear();
7800   myLastCreatedNodes.Clear();
7801
7802   MESSAGE("::SewFreeBorder()");
7803   Sew_Error aResult = SEW_OK;
7804
7805   // ====================================
7806   //    find side nodes and elements
7807   // ====================================
7808
7809   list< const SMDS_MeshNode* > nSide[ 2 ];
7810   list< const SMDS_MeshElement* > eSide[ 2 ];
7811   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7812   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7813
7814   // Free border 1
7815   // --------------
7816   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7817                       nSide[0], eSide[0])) {
7818     MESSAGE(" Free Border 1 not found " );
7819     aResult = SEW_BORDER1_NOT_FOUND;
7820   }
7821   if (theSideIsFreeBorder) {
7822     // Free border 2
7823     // --------------
7824     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7825                         nSide[1], eSide[1])) {
7826       MESSAGE(" Free Border 2 not found " );
7827       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7828     }
7829   }
7830   if ( aResult != SEW_OK )
7831     return aResult;
7832
7833   if (!theSideIsFreeBorder) {
7834     // Side 2
7835     // --------------
7836
7837     // -------------------------------------------------------------------------
7838     // Algo:
7839     // 1. If nodes to merge are not coincident, move nodes of the free border
7840     //    from the coord sys defined by the direction from the first to last
7841     //    nodes of the border to the correspondent sys of the side 2
7842     // 2. On the side 2, find the links most co-directed with the correspondent
7843     //    links of the free border
7844     // -------------------------------------------------------------------------
7845
7846     // 1. Since sewing may break if there are volumes to split on the side 2,
7847     //    we wont move nodes but just compute new coordinates for them
7848     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7849     TNodeXYZMap nBordXYZ;
7850     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7851     list< const SMDS_MeshNode* >::iterator nBordIt;
7852
7853     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7854     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7855     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7856     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7857     double tol2 = 1.e-8;
7858     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7859     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7860       // Need node movement.
7861
7862       // find X and Z axes to create trsf
7863       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7864       gp_Vec X = Zs ^ Zb;
7865       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7866         // Zb || Zs
7867         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7868
7869       // coord systems
7870       gp_Ax3 toBordAx( Pb1, Zb, X );
7871       gp_Ax3 fromSideAx( Ps1, Zs, X );
7872       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7873       // set trsf
7874       gp_Trsf toBordSys, fromSide2Sys;
7875       toBordSys.SetTransformation( toBordAx );
7876       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7877       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7878
7879       // move
7880       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7881         const SMDS_MeshNode* n = *nBordIt;
7882         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7883         toBordSys.Transforms( xyz );
7884         fromSide2Sys.Transforms( xyz );
7885         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7886       }
7887     }
7888     else {
7889       // just insert nodes XYZ in the nBordXYZ map
7890       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7891         const SMDS_MeshNode* n = *nBordIt;
7892         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7893       }
7894     }
7895
7896     // 2. On the side 2, find the links most co-directed with the correspondent
7897     //    links of the free border
7898
7899     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7900     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7901     sideNodes.push_back( theSideFirstNode );
7902
7903     bool hasVolumes = false;
7904     LinkID_Gen aLinkID_Gen( GetMeshDS() );
7905     set<long> foundSideLinkIDs, checkedLinkIDs;
7906     SMDS_VolumeTool volume;
7907     //const SMDS_MeshNode* faceNodes[ 4 ];
7908
7909     const SMDS_MeshNode*    sideNode;
7910     const SMDS_MeshElement* sideElem;
7911     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7912     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7913     nBordIt = bordNodes.begin();
7914     nBordIt++;
7915     // border node position and border link direction to compare with
7916     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7917     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7918     // choose next side node by link direction or by closeness to
7919     // the current border node:
7920     bool searchByDir = ( *nBordIt != theBordLastNode );
7921     do {
7922       // find the next node on the Side 2
7923       sideNode = 0;
7924       double maxDot = -DBL_MAX, minDist = DBL_MAX;
7925       long linkID;
7926       checkedLinkIDs.clear();
7927       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7928
7929       // loop on inverse elements of current node (prevSideNode) on the Side 2
7930       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7931       while ( invElemIt->more() )
7932       {
7933         const SMDS_MeshElement* elem = invElemIt->next();
7934         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7935         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7936         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7937         bool isVolume = volume.Set( elem );
7938         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7939         if ( isVolume ) // --volume
7940           hasVolumes = true;
7941         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7942           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7943           if(elem->IsQuadratic()) {
7944             const SMDS_VtkFace* F =
7945               dynamic_cast<const SMDS_VtkFace*>(elem);
7946             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7947             // use special nodes iterator
7948             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7949             while( anIter->more() ) {
7950               nodes[ iNode ] = cast2Node(anIter->next());
7951               if ( nodes[ iNode++ ] == prevSideNode )
7952                 iPrevNode = iNode - 1;
7953             }
7954           }
7955           else {
7956             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7957             while ( nIt->more() ) {
7958               nodes[ iNode ] = cast2Node( nIt->next() );
7959               if ( nodes[ iNode++ ] == prevSideNode )
7960                 iPrevNode = iNode - 1;
7961             }
7962           }
7963           // there are 2 links to check
7964           nbNodes = 2;
7965         }
7966         else // --edge
7967           continue;
7968         // loop on links, to be precise, on the second node of links
7969         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7970           const SMDS_MeshNode* n = nodes[ iNode ];
7971           if ( isVolume ) {
7972             if ( !volume.IsLinked( n, prevSideNode ))
7973               continue;
7974           }
7975           else {
7976             if ( iNode ) // a node before prevSideNode
7977               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7978             else         // a node after prevSideNode
7979               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7980           }
7981           // check if this link was already used
7982           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7983           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7984           if (!isJustChecked &&
7985               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7986           {
7987             // test a link geometrically
7988             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
7989             bool linkIsBetter = false;
7990             double dot = 0.0, dist = 0.0;
7991             if ( searchByDir ) { // choose most co-directed link
7992               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
7993               linkIsBetter = ( dot > maxDot );
7994             }
7995             else { // choose link with the node closest to bordPos
7996               dist = ( nextXYZ - bordPos ).SquareModulus();
7997               linkIsBetter = ( dist < minDist );
7998             }
7999             if ( linkIsBetter ) {
8000               maxDot = dot;
8001               minDist = dist;
8002               linkID = iLink;
8003               sideNode = n;
8004               sideElem = elem;
8005             }
8006           }
8007         }
8008       } // loop on inverse elements of prevSideNode
8009
8010       if ( !sideNode ) {
8011         MESSAGE(" Cant find path by links of the Side 2 ");
8012         return SEW_BAD_SIDE_NODES;
8013       }
8014       sideNodes.push_back( sideNode );
8015       sideElems.push_back( sideElem );
8016       foundSideLinkIDs.insert ( linkID );
8017       prevSideNode = sideNode;
8018
8019       if ( *nBordIt == theBordLastNode )
8020         searchByDir = false;
8021       else {
8022         // find the next border link to compare with
8023         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8024         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8025         // move to next border node if sideNode is before forward border node (bordPos)
8026         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8027           prevBordNode = *nBordIt;
8028           nBordIt++;
8029           bordPos = nBordXYZ[ *nBordIt ];
8030           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8031           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8032         }
8033       }
8034     }
8035     while ( sideNode != theSideSecondNode );
8036
8037     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8038       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8039       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8040     }
8041   } // end nodes search on the side 2
8042
8043   // ============================
8044   // sew the border to the side 2
8045   // ============================
8046
8047   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8048   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8049
8050   TListOfListOfNodes nodeGroupsToMerge;
8051   if ( nbNodes[0] == nbNodes[1] ||
8052        ( theSideIsFreeBorder && !theSideThirdNode)) {
8053
8054     // all nodes are to be merged
8055
8056     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8057          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8058          nIt[0]++, nIt[1]++ )
8059     {
8060       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8061       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8062       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8063     }
8064   }
8065   else {
8066
8067     // insert new nodes into the border and the side to get equal nb of segments
8068
8069     // get normalized parameters of nodes on the borders
8070     //double param[ 2 ][ maxNbNodes ];
8071     double* param[ 2 ];
8072     param[0] = new double [ maxNbNodes ];
8073     param[1] = new double [ maxNbNodes ];
8074     int iNode, iBord;
8075     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8076       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8077       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8078       const SMDS_MeshNode* nPrev = *nIt;
8079       double bordLength = 0;
8080       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8081         const SMDS_MeshNode* nCur = *nIt;
8082         gp_XYZ segment (nCur->X() - nPrev->X(),
8083                         nCur->Y() - nPrev->Y(),
8084                         nCur->Z() - nPrev->Z());
8085         double segmentLen = segment.Modulus();
8086         bordLength += segmentLen;
8087         param[ iBord ][ iNode ] = bordLength;
8088         nPrev = nCur;
8089       }
8090       // normalize within [0,1]
8091       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8092         param[ iBord ][ iNode ] /= bordLength;
8093       }
8094     }
8095
8096     // loop on border segments
8097     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8098     int i[ 2 ] = { 0, 0 };
8099     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8100     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8101
8102     TElemOfNodeListMap insertMap;
8103     TElemOfNodeListMap::iterator insertMapIt;
8104     // insertMap is
8105     // key:   elem to insert nodes into
8106     // value: 2 nodes to insert between + nodes to be inserted
8107     do {
8108       bool next[ 2 ] = { false, false };
8109
8110       // find min adjacent segment length after sewing
8111       double nextParam = 10., prevParam = 0;
8112       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8113         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8114           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8115         if ( i[ iBord ] > 0 )
8116           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8117       }
8118       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8119       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8120       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8121
8122       // choose to insert or to merge nodes
8123       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8124       if ( Abs( du ) <= minSegLen * 0.2 ) {
8125         // merge
8126         // ------
8127         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8128         const SMDS_MeshNode* n0 = *nIt[0];
8129         const SMDS_MeshNode* n1 = *nIt[1];
8130         nodeGroupsToMerge.back().push_back( n1 );
8131         nodeGroupsToMerge.back().push_back( n0 );
8132         // position of node of the border changes due to merge
8133         param[ 0 ][ i[0] ] += du;
8134         // move n1 for the sake of elem shape evaluation during insertion.
8135         // n1 will be removed by MergeNodes() anyway
8136         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8137         next[0] = next[1] = true;
8138       }
8139       else {
8140         // insert
8141         // ------
8142         int intoBord = ( du < 0 ) ? 0 : 1;
8143         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8144         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8145         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8146         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8147         if ( intoBord == 1 ) {
8148           // move node of the border to be on a link of elem of the side
8149           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8150           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8151           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8152           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8153           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8154         }
8155         insertMapIt = insertMap.find( elem );
8156         bool notFound = ( insertMapIt == insertMap.end() );
8157         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8158         if ( otherLink ) {
8159           // insert into another link of the same element:
8160           // 1. perform insertion into the other link of the elem
8161           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8162           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8163           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8164           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8165           // 2. perform insertion into the link of adjacent faces
8166           while (true) {
8167             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8168             if ( adjElem )
8169               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8170             else
8171               break;
8172           }
8173           if (toCreatePolyedrs) {
8174             // perform insertion into the links of adjacent volumes
8175             UpdateVolumes(n12, n22, nodeList);
8176           }
8177           // 3. find an element appeared on n1 and n2 after the insertion
8178           insertMap.erase( elem );
8179           elem = findAdjacentFace( n1, n2, 0 );
8180         }
8181         if ( notFound || otherLink ) {
8182           // add element and nodes of the side into the insertMap
8183           insertMapIt = insertMap.insert
8184             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8185           (*insertMapIt).second.push_back( n1 );
8186           (*insertMapIt).second.push_back( n2 );
8187         }
8188         // add node to be inserted into elem
8189         (*insertMapIt).second.push_back( nIns );
8190         next[ 1 - intoBord ] = true;
8191       }
8192
8193       // go to the next segment
8194       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8195         if ( next[ iBord ] ) {
8196           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8197             eIt[ iBord ]++;
8198           nPrev[ iBord ] = *nIt[ iBord ];
8199           nIt[ iBord ]++; i[ iBord ]++;
8200         }
8201       }
8202     }
8203     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8204
8205     // perform insertion of nodes into elements
8206
8207     for (insertMapIt = insertMap.begin();
8208          insertMapIt != insertMap.end();
8209          insertMapIt++ )
8210     {
8211       const SMDS_MeshElement* elem = (*insertMapIt).first;
8212       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8213       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8214       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8215
8216       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8217
8218       if ( !theSideIsFreeBorder ) {
8219         // look for and insert nodes into the faces adjacent to elem
8220         while (true) {
8221           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8222           if ( adjElem )
8223             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8224           else
8225             break;
8226         }
8227       }
8228       if (toCreatePolyedrs) {
8229         // perform insertion into the links of adjacent volumes
8230         UpdateVolumes(n1, n2, nodeList);
8231       }
8232     }
8233
8234     delete param[0];
8235     delete param[1];
8236   } // end: insert new nodes
8237
8238   MergeNodes ( nodeGroupsToMerge );
8239
8240   return aResult;
8241 }
8242
8243 //=======================================================================
8244 //function : InsertNodesIntoLink
8245 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8246 //           and theBetweenNode2 and split theElement
8247 //=======================================================================
8248
8249 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8250                                            const SMDS_MeshNode*        theBetweenNode1,
8251                                            const SMDS_MeshNode*        theBetweenNode2,
8252                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8253                                            const bool                  toCreatePoly)
8254 {
8255   if ( theFace->GetType() != SMDSAbs_Face ) return;
8256
8257   // find indices of 2 link nodes and of the rest nodes
8258   int iNode = 0, il1, il2, i3, i4;
8259   il1 = il2 = i3 = i4 = -1;
8260   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8261   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8262
8263   if(theFace->IsQuadratic()) {
8264     const SMDS_VtkFace* F =
8265       dynamic_cast<const SMDS_VtkFace*>(theFace);
8266     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8267     // use special nodes iterator
8268     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8269     while( anIter->more() ) {
8270       const SMDS_MeshNode* n = cast2Node(anIter->next());
8271       if ( n == theBetweenNode1 )
8272         il1 = iNode;
8273       else if ( n == theBetweenNode2 )
8274         il2 = iNode;
8275       else if ( i3 < 0 )
8276         i3 = iNode;
8277       else
8278         i4 = iNode;
8279       nodes[ iNode++ ] = n;
8280     }
8281   }
8282   else {
8283     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8284     while ( nodeIt->more() ) {
8285       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8286       if ( n == theBetweenNode1 )
8287         il1 = iNode;
8288       else if ( n == theBetweenNode2 )
8289         il2 = iNode;
8290       else if ( i3 < 0 )
8291         i3 = iNode;
8292       else
8293         i4 = iNode;
8294       nodes[ iNode++ ] = n;
8295     }
8296   }
8297   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8298     return ;
8299
8300   // arrange link nodes to go one after another regarding the face orientation
8301   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8302   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8303   if ( reverse ) {
8304     iNode = il1;
8305     il1 = il2;
8306     il2 = iNode;
8307     aNodesToInsert.reverse();
8308   }
8309   // check that not link nodes of a quadrangles are in good order
8310   int nbFaceNodes = theFace->NbNodes();
8311   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8312     iNode = i3;
8313     i3 = i4;
8314     i4 = iNode;
8315   }
8316
8317   if (toCreatePoly || theFace->IsPoly()) {
8318
8319     iNode = 0;
8320     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8321
8322     // add nodes of face up to first node of link
8323     bool isFLN = false;
8324
8325     if(theFace->IsQuadratic()) {
8326       const SMDS_VtkFace* F =
8327         dynamic_cast<const SMDS_VtkFace*>(theFace);
8328       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8329       // use special nodes iterator
8330       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8331       while( anIter->more()  && !isFLN ) {
8332         const SMDS_MeshNode* n = cast2Node(anIter->next());
8333         poly_nodes[iNode++] = n;
8334         if (n == nodes[il1]) {
8335           isFLN = true;
8336         }
8337       }
8338       // add nodes to insert
8339       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8340       for (; nIt != aNodesToInsert.end(); nIt++) {
8341         poly_nodes[iNode++] = *nIt;
8342       }
8343       // add nodes of face starting from last node of link
8344       while ( anIter->more() ) {
8345         poly_nodes[iNode++] = cast2Node(anIter->next());
8346       }
8347     }
8348     else {
8349       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8350       while ( nodeIt->more() && !isFLN ) {
8351         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8352         poly_nodes[iNode++] = n;
8353         if (n == nodes[il1]) {
8354           isFLN = true;
8355         }
8356       }
8357       // add nodes to insert
8358       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8359       for (; nIt != aNodesToInsert.end(); nIt++) {
8360         poly_nodes[iNode++] = *nIt;
8361       }
8362       // add nodes of face starting from last node of link
8363       while ( nodeIt->more() ) {
8364         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8365         poly_nodes[iNode++] = n;
8366       }
8367     }
8368
8369     // edit or replace the face
8370     SMESHDS_Mesh *aMesh = GetMeshDS();
8371
8372     if (theFace->IsPoly()) {
8373       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8374     }
8375     else {
8376       int aShapeId = FindShape( theFace );
8377
8378       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8379       myLastCreatedElems.Append(newElem);
8380       if ( aShapeId && newElem )
8381         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8382
8383       aMesh->RemoveElement(theFace);
8384     }
8385     return;
8386   }
8387
8388   SMESHDS_Mesh *aMesh = GetMeshDS();
8389   if( !theFace->IsQuadratic() ) {
8390
8391     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8392     int nbLinkNodes = 2 + aNodesToInsert.size();
8393     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8394     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8395     linkNodes[ 0 ] = nodes[ il1 ];
8396     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8397     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8398     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8399       linkNodes[ iNode++ ] = *nIt;
8400     }
8401     // decide how to split a quadrangle: compare possible variants
8402     // and choose which of splits to be a quadrangle
8403     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8404     if ( nbFaceNodes == 3 ) {
8405       iBestQuad = nbSplits;
8406       i4 = i3;
8407     }
8408     else if ( nbFaceNodes == 4 ) {
8409       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8410       double aBestRate = DBL_MAX;
8411       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8412         i1 = 0; i2 = 1;
8413         double aBadRate = 0;
8414         // evaluate elements quality
8415         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8416           if ( iSplit == iQuad ) {
8417             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8418                                    linkNodes[ i2++ ],
8419                                    nodes[ i3 ],
8420                                    nodes[ i4 ]);
8421             aBadRate += getBadRate( &quad, aCrit );
8422           }
8423           else {
8424             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8425                                    linkNodes[ i2++ ],
8426                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8427             aBadRate += getBadRate( &tria, aCrit );
8428           }
8429         }
8430         // choice
8431         if ( aBadRate < aBestRate ) {
8432           iBestQuad = iQuad;
8433           aBestRate = aBadRate;
8434         }
8435       }
8436     }
8437
8438     // create new elements
8439     int aShapeId = FindShape( theFace );
8440
8441     i1 = 0; i2 = 1;
8442     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8443       SMDS_MeshElement* newElem = 0;
8444       if ( iSplit == iBestQuad )
8445         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8446                                   linkNodes[ i2++ ],
8447                                   nodes[ i3 ],
8448                                   nodes[ i4 ]);
8449       else
8450         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8451                                   linkNodes[ i2++ ],
8452                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8453       myLastCreatedElems.Append(newElem);
8454       if ( aShapeId && newElem )
8455         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8456     }
8457
8458     // change nodes of theFace
8459     const SMDS_MeshNode* newNodes[ 4 ];
8460     newNodes[ 0 ] = linkNodes[ i1 ];
8461     newNodes[ 1 ] = linkNodes[ i2 ];
8462     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8463     newNodes[ 3 ] = nodes[ i4 ];
8464     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8465     const SMDS_MeshElement* newElem = 0;
8466     if (iSplit == iBestQuad)
8467       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8468     else
8469       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8470     myLastCreatedElems.Append(newElem);
8471     if ( aShapeId && newElem )
8472       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8473 } // end if(!theFace->IsQuadratic())
8474   else { // theFace is quadratic
8475     // we have to split theFace on simple triangles and one simple quadrangle
8476     int tmp = il1/2;
8477     int nbshift = tmp*2;
8478     // shift nodes in nodes[] by nbshift
8479     int i,j;
8480     for(i=0; i<nbshift; i++) {
8481       const SMDS_MeshNode* n = nodes[0];
8482       for(j=0; j<nbFaceNodes-1; j++) {
8483         nodes[j] = nodes[j+1];
8484       }
8485       nodes[nbFaceNodes-1] = n;
8486     }
8487     il1 = il1 - nbshift;
8488     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8489     //   n0      n1     n2    n0      n1     n2
8490     //     +-----+-----+        +-----+-----+
8491     //      \         /         |           |
8492     //       \       /          |           |
8493     //      n5+     +n3       n7+           +n3
8494     //         \   /            |           |
8495     //          \ /             |           |
8496     //           +              +-----+-----+
8497     //           n4           n6      n5     n4
8498
8499     // create new elements
8500     int aShapeId = FindShape( theFace );
8501
8502     int n1,n2,n3;
8503     if(nbFaceNodes==6) { // quadratic triangle
8504       SMDS_MeshElement* newElem =
8505         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8506       myLastCreatedElems.Append(newElem);
8507       if ( aShapeId && newElem )
8508         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8509       if(theFace->IsMediumNode(nodes[il1])) {
8510         // create quadrangle
8511         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8512         myLastCreatedElems.Append(newElem);
8513         if ( aShapeId && newElem )
8514           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8515         n1 = 1;
8516         n2 = 2;
8517         n3 = 3;
8518       }
8519       else {
8520         // create quadrangle
8521         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8522         myLastCreatedElems.Append(newElem);
8523         if ( aShapeId && newElem )
8524           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8525         n1 = 0;
8526         n2 = 1;
8527         n3 = 5;
8528       }
8529     }
8530     else { // nbFaceNodes==8 - quadratic quadrangle
8531       SMDS_MeshElement* newElem =
8532         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8533       myLastCreatedElems.Append(newElem);
8534       if ( aShapeId && newElem )
8535         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8536       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8537       myLastCreatedElems.Append(newElem);
8538       if ( aShapeId && newElem )
8539         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8540       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8541       myLastCreatedElems.Append(newElem);
8542       if ( aShapeId && newElem )
8543         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8544       if(theFace->IsMediumNode(nodes[il1])) {
8545         // create quadrangle
8546         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8547         myLastCreatedElems.Append(newElem);
8548         if ( aShapeId && newElem )
8549           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8550         n1 = 1;
8551         n2 = 2;
8552         n3 = 3;
8553       }
8554       else {
8555         // create quadrangle
8556         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8557         myLastCreatedElems.Append(newElem);
8558         if ( aShapeId && newElem )
8559           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8560         n1 = 0;
8561         n2 = 1;
8562         n3 = 7;
8563       }
8564     }
8565     // create needed triangles using n1,n2,n3 and inserted nodes
8566     int nbn = 2 + aNodesToInsert.size();
8567     //const SMDS_MeshNode* aNodes[nbn];
8568     vector<const SMDS_MeshNode*> aNodes(nbn);
8569     aNodes[0] = nodes[n1];
8570     aNodes[nbn-1] = nodes[n2];
8571     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8572     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8573       aNodes[iNode++] = *nIt;
8574     }
8575     for(i=1; i<nbn; i++) {
8576       SMDS_MeshElement* newElem =
8577         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8578       myLastCreatedElems.Append(newElem);
8579       if ( aShapeId && newElem )
8580         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8581     }
8582   }
8583   // remove old face
8584   aMesh->RemoveElement(theFace);
8585 }
8586
8587 //=======================================================================
8588 //function : UpdateVolumes
8589 //purpose  :
8590 //=======================================================================
8591 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8592                                       const SMDS_MeshNode*        theBetweenNode2,
8593                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8594 {
8595   myLastCreatedElems.Clear();
8596   myLastCreatedNodes.Clear();
8597
8598   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8599   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8600     const SMDS_MeshElement* elem = invElemIt->next();
8601
8602     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8603     SMDS_VolumeTool aVolume (elem);
8604     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8605       continue;
8606
8607     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8608     int iface, nbFaces = aVolume.NbFaces();
8609     vector<const SMDS_MeshNode *> poly_nodes;
8610     vector<int> quantities (nbFaces);
8611
8612     for (iface = 0; iface < nbFaces; iface++) {
8613       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8614       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8615       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8616
8617       for (int inode = 0; inode < nbFaceNodes; inode++) {
8618         poly_nodes.push_back(faceNodes[inode]);
8619
8620         if (nbInserted == 0) {
8621           if (faceNodes[inode] == theBetweenNode1) {
8622             if (faceNodes[inode + 1] == theBetweenNode2) {
8623               nbInserted = theNodesToInsert.size();
8624
8625               // add nodes to insert
8626               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8627               for (; nIt != theNodesToInsert.end(); nIt++) {
8628                 poly_nodes.push_back(*nIt);
8629               }
8630             }
8631           }
8632           else if (faceNodes[inode] == theBetweenNode2) {
8633             if (faceNodes[inode + 1] == theBetweenNode1) {
8634               nbInserted = theNodesToInsert.size();
8635
8636               // add nodes to insert in reversed order
8637               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8638               nIt--;
8639               for (; nIt != theNodesToInsert.begin(); nIt--) {
8640                 poly_nodes.push_back(*nIt);
8641               }
8642               poly_nodes.push_back(*nIt);
8643             }
8644           }
8645           else {
8646           }
8647         }
8648       }
8649       quantities[iface] = nbFaceNodes + nbInserted;
8650     }
8651
8652     // Replace or update the volume
8653     SMESHDS_Mesh *aMesh = GetMeshDS();
8654
8655     if (elem->IsPoly()) {
8656       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8657
8658     }
8659     else {
8660       int aShapeId = FindShape( elem );
8661
8662       SMDS_MeshElement* newElem =
8663         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8664       myLastCreatedElems.Append(newElem);
8665       if (aShapeId && newElem)
8666         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8667
8668       aMesh->RemoveElement(elem);
8669     }
8670   }
8671 }
8672
8673 namespace
8674 {
8675   //================================================================================
8676   /*!
8677    * \brief Transform any volume into data of SMDSEntity_Polyhedra
8678    */
8679   //================================================================================
8680
8681   void volumeToPolyhedron( const SMDS_MeshElement*         elem,
8682                            vector<const SMDS_MeshNode *> & nodes,
8683                            vector<int> &                   nbNodeInFaces )
8684   {
8685     nodes.clear();
8686     nbNodeInFaces.clear();
8687     SMDS_VolumeTool vTool ( elem );
8688     for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
8689     {
8690       const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
8691       nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
8692       nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
8693     }
8694   }
8695 }
8696
8697 //=======================================================================
8698 /*!
8699  * \brief Convert elements contained in a submesh to quadratic
8700  * \return int - nb of checked elements
8701  */
8702 //=======================================================================
8703
8704 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8705                                              SMESH_MesherHelper& theHelper,
8706                                              const bool          theForce3d)
8707 {
8708   int nbElem = 0;
8709   if( !theSm ) return nbElem;
8710
8711   vector<int> nbNodeInFaces;
8712   vector<const SMDS_MeshNode *> nodes;
8713   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8714   while(ElemItr->more())
8715   {
8716     nbElem++;
8717     const SMDS_MeshElement* elem = ElemItr->next();
8718     if( !elem ) continue;
8719
8720     // analyse a necessity of conversion
8721     const SMDSAbs_ElementType aType = elem->GetType();
8722     if ( aType < SMDSAbs_Edge || aType > SMDSAbs_Volume )
8723       continue;
8724     const SMDSAbs_EntityType aGeomType = elem->GetEntityType();
8725     bool hasCentralNodes = false;
8726     if ( elem->IsQuadratic() )
8727     {
8728       bool alreadyOK;
8729       switch ( aGeomType ) {
8730       case SMDSEntity_Quad_Triangle:
8731       case SMDSEntity_Quad_Quadrangle:
8732       case SMDSEntity_Quad_Hexa:
8733         alreadyOK = !theHelper.GetIsBiQuadratic(); break;
8734
8735       case SMDSEntity_BiQuad_Triangle:
8736       case SMDSEntity_BiQuad_Quadrangle:
8737       case SMDSEntity_TriQuad_Hexa:
8738         alreadyOK = theHelper.GetIsBiQuadratic();
8739         hasCentralNodes = true;
8740         break;
8741       default:
8742         alreadyOK = true;
8743       }
8744       // take into account already present modium nodes
8745       switch ( aType ) {
8746       case SMDSAbs_Volume:
8747         theHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( elem )); break;
8748       case SMDSAbs_Face:
8749         theHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem )); break;
8750       case SMDSAbs_Edge:
8751         theHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( elem )); break;
8752       default:;
8753       }
8754       if ( alreadyOK )
8755         continue;
8756     }
8757     // get elem data needed to re-create it
8758     //
8759     const int id      = elem->GetID();
8760     const int nbNodes = elem->NbCornerNodes();
8761     nodes.assign(elem->begin_nodes(), elem->end_nodes());
8762     if ( aGeomType == SMDSEntity_Polyhedra )
8763       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
8764     else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
8765       volumeToPolyhedron( elem, nodes, nbNodeInFaces );
8766
8767     // remove a linear element
8768     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
8769
8770     // remove central nodes of biquadratic elements (biquad->quad convertion)
8771     if ( hasCentralNodes )
8772       for ( size_t i = nbNodes * 2; i < nodes.size(); ++i )
8773         if ( nodes[i]->NbInverseElements() == 0 )
8774           GetMeshDS()->RemoveFreeNode( nodes[i], theSm, /*fromGroups=*/true );
8775
8776     const SMDS_MeshElement* NewElem = 0;
8777
8778     switch( aType )
8779     {
8780     case SMDSAbs_Edge :
8781       {
8782         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8783         break;
8784       }
8785     case SMDSAbs_Face :
8786       {
8787         switch(nbNodes)
8788         {
8789         case 3:
8790           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8791           break;
8792         case 4:
8793           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8794           break;
8795         default:
8796           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
8797         }
8798         break;
8799       }
8800     case SMDSAbs_Volume :
8801       {
8802         switch( aGeomType )
8803         {
8804         case SMDSEntity_Tetra:
8805           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8806           break;
8807         case SMDSEntity_Pyramid:
8808           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
8809           break;
8810         case SMDSEntity_Penta:
8811           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
8812           break;
8813         case SMDSEntity_Hexa:
8814         case SMDSEntity_Quad_Hexa:
8815         case SMDSEntity_TriQuad_Hexa:
8816           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8817                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8818           break;
8819         case SMDSEntity_Hexagonal_Prism:
8820         default:
8821           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8822         }
8823         break;
8824       }
8825     default :
8826       continue;
8827     }
8828     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8829     if( NewElem && NewElem->getshapeId() < 1 )
8830       theSm->AddElement( NewElem );
8831   }
8832   return nbElem;
8833 }
8834 //=======================================================================
8835 //function : ConvertToQuadratic
8836 //purpose  :
8837 //=======================================================================
8838
8839 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad)
8840 {
8841   SMESHDS_Mesh* meshDS = GetMeshDS();
8842
8843   SMESH_MesherHelper aHelper(*myMesh);
8844
8845   aHelper.SetIsQuadratic( true );
8846   aHelper.SetIsBiQuadratic( theToBiQuad );
8847   aHelper.SetElementsOnShape(true);
8848   aHelper.ToFixNodeParameters( true );
8849
8850   // convert elements assigned to sub-meshes
8851   int nbCheckedElems = 0;
8852   if ( myMesh->HasShapeToMesh() )
8853   {
8854     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8855     {
8856       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8857       while ( smIt->more() ) {
8858         SMESH_subMesh* sm = smIt->next();
8859         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8860           aHelper.SetSubShape( sm->GetSubShape() );
8861           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8862         }
8863       }
8864     }
8865   }
8866
8867   // convert elements NOT assigned to sub-meshes
8868   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8869   if ( nbCheckedElems < totalNbElems ) // not all elements are in sub-meshes
8870   {
8871     aHelper.SetElementsOnShape(false);
8872     SMESHDS_SubMesh *smDS = 0;
8873
8874     // convert edges
8875     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8876     while( aEdgeItr->more() )
8877     {
8878       const SMDS_MeshEdge* edge = aEdgeItr->next();
8879       if ( !edge->IsQuadratic() )
8880       {
8881         int                  id = edge->GetID();
8882         const SMDS_MeshNode* n1 = edge->GetNode(0);
8883         const SMDS_MeshNode* n2 = edge->GetNode(1);
8884
8885         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
8886
8887         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8888         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8889       }
8890       else
8891       {
8892         aHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( edge ));
8893       }
8894     }
8895
8896     // convert faces
8897     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8898     while( aFaceItr->more() )
8899     {
8900       const SMDS_MeshFace* face = aFaceItr->next();
8901       if ( !face ) continue;
8902       
8903       const SMDSAbs_EntityType type = face->GetEntityType();
8904       bool alreadyOK;
8905       switch( type )
8906       {
8907       case SMDSEntity_Quad_Triangle:
8908       case SMDSEntity_Quad_Quadrangle:
8909         alreadyOK = !theToBiQuad;
8910         aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
8911         break;
8912       case SMDSEntity_BiQuad_Triangle:
8913       case SMDSEntity_BiQuad_Quadrangle:
8914         alreadyOK = theToBiQuad;
8915         aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
8916         break;
8917       default: alreadyOK = false;
8918       }
8919       if ( alreadyOK )
8920         continue;
8921
8922       const int id = face->GetID();
8923       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
8924
8925       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
8926
8927       SMDS_MeshFace * NewFace = 0;
8928       switch( type )
8929       {
8930       case SMDSEntity_Triangle:
8931       case SMDSEntity_Quad_Triangle:
8932       case SMDSEntity_BiQuad_Triangle:
8933         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8934         if ( nodes.size() == 7 && nodes[6]->NbInverseElements() == 0 ) // rm a central node
8935           GetMeshDS()->RemoveFreeNode( nodes[6], /*sm=*/0, /*fromGroups=*/true );
8936         break;
8937
8938       case SMDSEntity_Quadrangle:
8939       case SMDSEntity_Quad_Quadrangle:
8940       case SMDSEntity_BiQuad_Quadrangle:
8941         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8942         if ( nodes.size() == 9 && nodes[8]->NbInverseElements() == 0 ) // rm a central node
8943           GetMeshDS()->RemoveFreeNode( nodes[8], /*sm=*/0, /*fromGroups=*/true );
8944         break;
8945
8946       default:;
8947         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
8948       }
8949       ReplaceElemInGroups( face, NewFace, GetMeshDS());
8950     }
8951
8952     // convert volumes
8953     vector<int> nbNodeInFaces;
8954     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8955     while(aVolumeItr->more())
8956     {
8957       const SMDS_MeshVolume* volume = aVolumeItr->next();
8958       if ( !volume ) continue;
8959
8960       const SMDSAbs_EntityType type = volume->GetEntityType();
8961       if ( volume->IsQuadratic() )
8962       {
8963         bool alreadyOK;
8964         switch ( type )
8965         {
8966         case SMDSEntity_Quad_Hexa:    alreadyOK = !theToBiQuad; break;
8967         case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; break;
8968         default:                      alreadyOK = true;
8969         }
8970         if ( alreadyOK )
8971         {
8972           aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume ));
8973           continue;
8974         }
8975       }
8976       const int id = volume->GetID();
8977       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
8978       if ( type == SMDSEntity_Polyhedra )
8979         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
8980       else if ( type == SMDSEntity_Hexagonal_Prism )
8981         volumeToPolyhedron( volume, nodes, nbNodeInFaces );
8982
8983       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
8984
8985       SMDS_MeshVolume * NewVolume = 0;
8986       switch ( type )
8987       {
8988       case SMDSEntity_Tetra:
8989         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
8990         break;
8991       case SMDSEntity_Hexa:
8992       case SMDSEntity_Quad_Hexa:
8993       case SMDSEntity_TriQuad_Hexa:
8994         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8995                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8996         for ( size_t i = 20; i < nodes.size(); ++i ) // rm central nodes
8997           if ( nodes[i]->NbInverseElements() == 0 )
8998             GetMeshDS()->RemoveFreeNode( nodes[i], /*sm=*/0, /*fromGroups=*/true );
8999         break;
9000       case SMDSEntity_Pyramid:
9001         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9002                                       nodes[3], nodes[4], id, theForce3d);
9003         break;
9004       case SMDSEntity_Penta:
9005         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9006                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9007         break;
9008       case SMDSEntity_Hexagonal_Prism:
9009       default:
9010         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9011       }
9012       ReplaceElemInGroups(volume, NewVolume, meshDS);
9013     }
9014   }
9015
9016   if ( !theForce3d )
9017   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9018     // aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9019     // aHelper.FixQuadraticElements(myError);
9020     SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
9021   }
9022 }
9023
9024 //================================================================================
9025 /*!
9026  * \brief Makes given elements quadratic
9027  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9028  *  \param theElements - elements to make quadratic
9029  */
9030 //================================================================================
9031
9032 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9033                                           TIDSortedElemSet& theElements,
9034                                           const bool        theToBiQuad)
9035 {
9036   if ( theElements.empty() ) return;
9037
9038   // we believe that all theElements are of the same type
9039   const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9040
9041   // get all nodes shared by theElements
9042   TIDSortedNodeSet allNodes;
9043   TIDSortedElemSet::iterator eIt = theElements.begin();
9044   for ( ; eIt != theElements.end(); ++eIt )
9045     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9046
9047   // complete theElements with elements of lower dim whose all nodes are in allNodes
9048
9049   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9050   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9051   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9052   for ( ; nIt != allNodes.end(); ++nIt )
9053   {
9054     const SMDS_MeshNode* n = *nIt;
9055     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9056     while ( invIt->more() )
9057     {
9058       const SMDS_MeshElement*      e = invIt->next();
9059       const SMDSAbs_ElementType type = e->GetType();
9060       if ( e->IsQuadratic() )
9061       {
9062         quadAdjacentElems[ type ].insert( e );
9063
9064         bool alreadyOK;
9065         switch ( e->GetEntityType() ) {
9066         case SMDSEntity_Quad_Triangle:
9067         case SMDSEntity_Quad_Quadrangle:
9068         case SMDSEntity_Quad_Hexa:         alreadyOK = !theToBiQuad; break;
9069         case SMDSEntity_BiQuad_Triangle:
9070         case SMDSEntity_BiQuad_Quadrangle:
9071         case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; break;
9072         default:                           alreadyOK = true;
9073         }
9074         if ( alreadyOK )
9075           continue;
9076       }
9077       if ( type >= elemType )
9078         continue; // same type or more complex linear element
9079
9080       if ( !checkedAdjacentElems[ type ].insert( e ).second )
9081         continue; // e is already checked
9082
9083       // check nodes
9084       bool allIn = true;
9085       SMDS_NodeIteratorPtr nodeIt = e->nodeIterator();
9086       while ( nodeIt->more() && allIn )
9087         allIn = allNodes.count( nodeIt->next() );
9088       if ( allIn )
9089         theElements.insert(e );
9090     }
9091   }
9092
9093   SMESH_MesherHelper helper(*myMesh);
9094   helper.SetIsQuadratic( true );
9095   helper.SetIsBiQuadratic( theToBiQuad );
9096
9097   // add links of quadratic adjacent elements to the helper
9098
9099   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9100     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9101           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9102     {
9103       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9104     }
9105   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9106     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9107           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9108     {
9109       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9110     }
9111   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9112     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9113           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9114     {
9115       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9116     }
9117
9118   // make quadratic (or bi-tri-quadratic) elements instead of linear ones
9119
9120   SMESHDS_Mesh*  meshDS = GetMeshDS();
9121   SMESHDS_SubMesh* smDS = 0;
9122   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9123   {
9124     const SMDS_MeshElement* elem = *eIt;
9125
9126     bool alreadyOK;
9127     int nbCentralNodes = 0;
9128     switch ( elem->GetEntityType() ) {
9129       // linear convertible
9130     case SMDSEntity_Edge:
9131     case SMDSEntity_Triangle:
9132     case SMDSEntity_Quadrangle:
9133     case SMDSEntity_Tetra:
9134     case SMDSEntity_Pyramid:
9135     case SMDSEntity_Hexa:
9136     case SMDSEntity_Penta:             alreadyOK = false;       nbCentralNodes = 0; break;
9137       // quadratic that can become bi-quadratic
9138     case SMDSEntity_Quad_Triangle:
9139     case SMDSEntity_Quad_Quadrangle:
9140     case SMDSEntity_Quad_Hexa:         alreadyOK =!theToBiQuad; nbCentralNodes = 0; break;
9141       // bi-quadratic
9142     case SMDSEntity_BiQuad_Triangle:
9143     case SMDSEntity_BiQuad_Quadrangle: alreadyOK = theToBiQuad; nbCentralNodes = 1; break;
9144     case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; nbCentralNodes = 7; break;
9145       // the rest
9146     default:                           alreadyOK = true;
9147     }
9148     if ( alreadyOK ) continue;
9149
9150     const SMDSAbs_ElementType type = elem->GetType();
9151     const int                   id = elem->GetID();
9152     const int              nbNodes = elem->NbCornerNodes();
9153     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9154
9155     helper.SetSubShape( elem->getshapeId() );
9156
9157     if ( !smDS || !smDS->Contains( elem ))
9158       smDS = meshDS->MeshElements( elem->getshapeId() );
9159     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9160
9161     SMDS_MeshElement * newElem = 0;
9162     switch( nbNodes )
9163     {
9164     case 4: // cases for most frequently used element types go first (for optimization)
9165       if ( type == SMDSAbs_Volume )
9166         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9167       else
9168         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9169       break;
9170     case 8:
9171       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9172                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9173       break;
9174     case 3:
9175       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9176       break;
9177     case 2:
9178       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9179       break;
9180     case 5:
9181       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9182                                  nodes[4], id, theForce3d);
9183       break;
9184     case 6:
9185       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9186                                  nodes[4], nodes[5], id, theForce3d);
9187       break;
9188     default:;
9189     }
9190     ReplaceElemInGroups( elem, newElem, meshDS);
9191     if( newElem && smDS )
9192       smDS->AddElement( newElem );
9193
9194      // remove central nodes
9195     for ( size_t i = nodes.size() - nbCentralNodes; i < nodes.size(); ++i )
9196       if ( nodes[i]->NbInverseElements() == 0 )
9197         meshDS->RemoveFreeNode( nodes[i], smDS, /*fromGroups=*/true );
9198
9199   } // loop on theElements
9200
9201   if ( !theForce3d )
9202   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9203     // helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9204     // helper.FixQuadraticElements( myError );
9205     SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
9206   }
9207 }
9208
9209 //=======================================================================
9210 /*!
9211  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9212  * \return int - nb of checked elements
9213  */
9214 //=======================================================================
9215
9216 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9217                                      SMDS_ElemIteratorPtr theItr,
9218                                      const int            theShapeID)
9219 {
9220   int nbElem = 0;
9221   SMESHDS_Mesh* meshDS = GetMeshDS();
9222
9223   while( theItr->more() )
9224   {
9225     const SMDS_MeshElement* elem = theItr->next();
9226     nbElem++;
9227     if( elem && elem->IsQuadratic())
9228     {
9229       int id                    = elem->GetID();
9230       int nbCornerNodes         = elem->NbCornerNodes();
9231       SMDSAbs_ElementType aType = elem->GetType();
9232
9233       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9234
9235       //remove a quadratic element
9236       if ( !theSm || !theSm->Contains( elem ))
9237         theSm = meshDS->MeshElements( elem->getshapeId() );
9238       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9239
9240       // remove medium nodes
9241       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9242         if ( nodes[i]->NbInverseElements() == 0 )
9243           meshDS->RemoveFreeNode( nodes[i], theSm );
9244
9245       // add a linear element
9246       nodes.resize( nbCornerNodes );
9247       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9248       ReplaceElemInGroups(elem, newElem, meshDS);
9249       if( theSm && newElem )
9250         theSm->AddElement( newElem );
9251     }
9252   }
9253   return nbElem;
9254 }
9255
9256 //=======================================================================
9257 //function : ConvertFromQuadratic
9258 //purpose  :
9259 //=======================================================================
9260
9261 bool SMESH_MeshEditor::ConvertFromQuadratic()
9262 {
9263   int nbCheckedElems = 0;
9264   if ( myMesh->HasShapeToMesh() )
9265   {
9266     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9267     {
9268       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9269       while ( smIt->more() ) {
9270         SMESH_subMesh* sm = smIt->next();
9271         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9272           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9273       }
9274     }
9275   }
9276
9277   int totalNbElems =
9278     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9279   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9280   {
9281     SMESHDS_SubMesh *aSM = 0;
9282     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9283   }
9284
9285   return true;
9286 }
9287
9288 namespace
9289 {
9290   //================================================================================
9291   /*!
9292    * \brief Return true if all medium nodes of the element are in the node set
9293    */
9294   //================================================================================
9295
9296   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9297   {
9298     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9299       if ( !nodeSet.count( elem->GetNode(i) ))
9300         return false;
9301     return true;
9302   }
9303 }
9304
9305 //================================================================================
9306 /*!
9307  * \brief Makes given elements linear
9308  */
9309 //================================================================================
9310
9311 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9312 {
9313   if ( theElements.empty() ) return;
9314
9315   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9316   set<int> mediumNodeIDs;
9317   TIDSortedElemSet::iterator eIt = theElements.begin();
9318   for ( ; eIt != theElements.end(); ++eIt )
9319   {
9320     const SMDS_MeshElement* e = *eIt;
9321     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9322       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9323   }
9324
9325   // replace given elements by linear ones
9326   SMDS_ElemIteratorPtr elemIt = elemSetIterator( theElements );
9327   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9328
9329   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9330   // except those elements sharing medium nodes of quadratic element whose medium nodes
9331   // are not all in mediumNodeIDs
9332
9333   // get remaining medium nodes
9334   TIDSortedNodeSet mediumNodes;
9335   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9336   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9337     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9338       mediumNodes.insert( mediumNodes.end(), n );
9339
9340   // find more quadratic elements to convert
9341   TIDSortedElemSet moreElemsToConvert;
9342   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9343   for ( ; nIt != mediumNodes.end(); ++nIt )
9344   {
9345     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9346     while ( invIt->more() )
9347     {
9348       const SMDS_MeshElement* e = invIt->next();
9349       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9350       {
9351         // find a more complex element including e and
9352         // whose medium nodes are not in mediumNodes
9353         bool complexFound = false;
9354         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9355         {
9356           SMDS_ElemIteratorPtr invIt2 =
9357             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9358           while ( invIt2->more() )
9359           {
9360             const SMDS_MeshElement* eComplex = invIt2->next();
9361             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9362             {
9363               int nbCommonNodes = SMESH_MeshAlgos::GetCommonNodes( e, eComplex ).size();
9364               if ( nbCommonNodes == e->NbNodes())
9365               {
9366                 complexFound = true;
9367                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9368                 break;
9369               }
9370             }
9371           }
9372         }
9373         if ( !complexFound )
9374           moreElemsToConvert.insert( e );
9375       }
9376     }
9377   }
9378   elemIt = elemSetIterator( moreElemsToConvert );
9379   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9380 }
9381
9382 //=======================================================================
9383 //function : SewSideElements
9384 //purpose  :
9385 //=======================================================================
9386
9387 SMESH_MeshEditor::Sew_Error
9388 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9389                                    TIDSortedElemSet&    theSide2,
9390                                    const SMDS_MeshNode* theFirstNode1,
9391                                    const SMDS_MeshNode* theFirstNode2,
9392                                    const SMDS_MeshNode* theSecondNode1,
9393                                    const SMDS_MeshNode* theSecondNode2)
9394 {
9395   myLastCreatedElems.Clear();
9396   myLastCreatedNodes.Clear();
9397
9398   MESSAGE ("::::SewSideElements()");
9399   if ( theSide1.size() != theSide2.size() )
9400     return SEW_DIFF_NB_OF_ELEMENTS;
9401
9402   Sew_Error aResult = SEW_OK;
9403   // Algo:
9404   // 1. Build set of faces representing each side
9405   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9406   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9407
9408   // =======================================================================
9409   // 1. Build set of faces representing each side:
9410   // =======================================================================
9411   // a. build set of nodes belonging to faces
9412   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9413   // c. create temporary faces representing side of volumes if correspondent
9414   //    face does not exist
9415
9416   SMESHDS_Mesh* aMesh = GetMeshDS();
9417   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9418   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9419   TIDSortedElemSet             faceSet1, faceSet2;
9420   set<const SMDS_MeshElement*> volSet1,  volSet2;
9421   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9422   TIDSortedElemSet             * faceSetPtr[] = { &faceSet1, &faceSet2 };
9423   set<const SMDS_MeshElement*> *  volSetPtr[] = { &volSet1,  &volSet2  };
9424   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9425   TIDSortedElemSet             * elemSetPtr[] = { &theSide1, &theSide2 };
9426   int iSide, iFace, iNode;
9427
9428   list<const SMDS_MeshElement* > tempFaceList;
9429   for ( iSide = 0; iSide < 2; iSide++ ) {
9430     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9431     TIDSortedElemSet             * elemSet = elemSetPtr[ iSide ];
9432     TIDSortedElemSet             * faceSet = faceSetPtr[ iSide ];
9433     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9434     set<const SMDS_MeshElement*>::iterator vIt;
9435     TIDSortedElemSet::iterator eIt;
9436     set<const SMDS_MeshNode*>::iterator    nIt;
9437
9438     // check that given nodes belong to given elements
9439     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9440     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9441     int firstIndex = -1, secondIndex = -1;
9442     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9443       const SMDS_MeshElement* elem = *eIt;
9444       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9445       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9446       if ( firstIndex > -1 && secondIndex > -1 ) break;
9447     }
9448     if ( firstIndex < 0 || secondIndex < 0 ) {
9449       // we can simply return until temporary faces created
9450       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9451     }
9452
9453     // -----------------------------------------------------------
9454     // 1a. Collect nodes of existing faces
9455     //     and build set of face nodes in order to detect missing
9456     //     faces corresponding to sides of volumes
9457     // -----------------------------------------------------------
9458
9459     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9460
9461     // loop on the given element of a side
9462     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9463       //const SMDS_MeshElement* elem = *eIt;
9464       const SMDS_MeshElement* elem = *eIt;
9465       if ( elem->GetType() == SMDSAbs_Face ) {
9466         faceSet->insert( elem );
9467         set <const SMDS_MeshNode*> faceNodeSet;
9468         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9469         while ( nodeIt->more() ) {
9470           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9471           nodeSet->insert( n );
9472           faceNodeSet.insert( n );
9473         }
9474         setOfFaceNodeSet.insert( faceNodeSet );
9475       }
9476       else if ( elem->GetType() == SMDSAbs_Volume )
9477         volSet->insert( elem );
9478     }
9479     // ------------------------------------------------------------------------------
9480     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9481     // ------------------------------------------------------------------------------
9482
9483     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9484       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9485       while ( fIt->more() ) { // loop on faces sharing a node
9486         const SMDS_MeshElement* f = fIt->next();
9487         if ( faceSet->find( f ) == faceSet->end() ) {
9488           // check if all nodes are in nodeSet and
9489           // complete setOfFaceNodeSet if they are
9490           set <const SMDS_MeshNode*> faceNodeSet;
9491           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9492           bool allInSet = true;
9493           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9494             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9495             if ( nodeSet->find( n ) == nodeSet->end() )
9496               allInSet = false;
9497             else
9498               faceNodeSet.insert( n );
9499           }
9500           if ( allInSet ) {
9501             faceSet->insert( f );
9502             setOfFaceNodeSet.insert( faceNodeSet );
9503           }
9504         }
9505       }
9506     }
9507
9508     // -------------------------------------------------------------------------
9509     // 1c. Create temporary faces representing sides of volumes if correspondent
9510     //     face does not exist
9511     // -------------------------------------------------------------------------
9512
9513     if ( !volSet->empty() ) {
9514       //int nodeSetSize = nodeSet->size();
9515
9516       // loop on given volumes
9517       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9518         SMDS_VolumeTool vol (*vIt);
9519         // loop on volume faces: find free faces
9520         // --------------------------------------
9521         list<const SMDS_MeshElement* > freeFaceList;
9522         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9523           if ( !vol.IsFreeFace( iFace ))
9524             continue;
9525           // check if there is already a face with same nodes in a face set
9526           const SMDS_MeshElement* aFreeFace = 0;
9527           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9528           int nbNodes = vol.NbFaceNodes( iFace );
9529           set <const SMDS_MeshNode*> faceNodeSet;
9530           vol.GetFaceNodes( iFace, faceNodeSet );
9531           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9532           if ( isNewFace ) {
9533             // no such a face is given but it still can exist, check it
9534             vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
9535             aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
9536           }
9537           if ( !aFreeFace ) {
9538             // create a temporary face
9539             if ( nbNodes == 3 ) {
9540               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9541               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9542             }
9543             else if ( nbNodes == 4 ) {
9544               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9545               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9546             }
9547             else {
9548               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9549               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9550               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9551             }
9552             if ( aFreeFace )
9553               tempFaceList.push_back( aFreeFace );
9554           }
9555
9556           if ( aFreeFace )
9557             freeFaceList.push_back( aFreeFace );
9558
9559         } // loop on faces of a volume
9560
9561         // choose one of several free faces of a volume
9562         // --------------------------------------------
9563         if ( freeFaceList.size() > 1 ) {
9564           // choose a face having max nb of nodes shared by other elems of a side
9565           int maxNbNodes = -1;
9566           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9567           while ( fIt != freeFaceList.end() ) { // loop on free faces
9568             int nbSharedNodes = 0;
9569             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9570             while ( nodeIt->more() ) { // loop on free face nodes
9571               const SMDS_MeshNode* n =
9572                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9573               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9574               while ( invElemIt->more() ) {
9575                 const SMDS_MeshElement* e = invElemIt->next();
9576                 nbSharedNodes += faceSet->count( e );
9577                 nbSharedNodes += elemSet->count( e );
9578               }
9579             }
9580             if ( nbSharedNodes > maxNbNodes ) {
9581               maxNbNodes = nbSharedNodes;
9582               freeFaceList.erase( freeFaceList.begin(), fIt++ );
9583             }
9584             else if ( nbSharedNodes == maxNbNodes ) {
9585               fIt++;
9586             }
9587             else {
9588               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9589             }
9590           }
9591           if ( freeFaceList.size() > 1 )
9592           {
9593             // could not choose one face, use another way
9594             // choose a face most close to the bary center of the opposite side
9595             gp_XYZ aBC( 0., 0., 0. );
9596             set <const SMDS_MeshNode*> addedNodes;
9597             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9598             eIt = elemSet2->begin();
9599             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9600               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9601               while ( nodeIt->more() ) { // loop on free face nodes
9602                 const SMDS_MeshNode* n =
9603                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9604                 if ( addedNodes.insert( n ).second )
9605                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9606               }
9607             }
9608             aBC /= addedNodes.size();
9609             double minDist = DBL_MAX;
9610             fIt = freeFaceList.begin();
9611             while ( fIt != freeFaceList.end() ) { // loop on free faces
9612               double dist = 0;
9613               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9614               while ( nodeIt->more() ) { // loop on free face nodes
9615                 const SMDS_MeshNode* n =
9616                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9617                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9618                 dist += ( aBC - p ).SquareModulus();
9619               }
9620               if ( dist < minDist ) {
9621                 minDist = dist;
9622                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9623               }
9624               else
9625                 fIt = freeFaceList.erase( fIt++ );
9626             }
9627           }
9628         } // choose one of several free faces of a volume
9629
9630         if ( freeFaceList.size() == 1 ) {
9631           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9632           faceSet->insert( aFreeFace );
9633           // complete a node set with nodes of a found free face
9634           //           for ( iNode = 0; iNode < ; iNode++ )
9635           //             nodeSet->insert( fNodes[ iNode ] );
9636         }
9637
9638       } // loop on volumes of a side
9639
9640       //       // complete a set of faces if new nodes in a nodeSet appeared
9641       //       // ----------------------------------------------------------
9642       //       if ( nodeSetSize != nodeSet->size() ) {
9643       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9644       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9645       //           while ( fIt->more() ) { // loop on faces sharing a node
9646       //             const SMDS_MeshElement* f = fIt->next();
9647       //             if ( faceSet->find( f ) == faceSet->end() ) {
9648       //               // check if all nodes are in nodeSet and
9649       //               // complete setOfFaceNodeSet if they are
9650       //               set <const SMDS_MeshNode*> faceNodeSet;
9651       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9652       //               bool allInSet = true;
9653       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9654       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9655       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9656       //                   allInSet = false;
9657       //                 else
9658       //                   faceNodeSet.insert( n );
9659       //               }
9660       //               if ( allInSet ) {
9661       //                 faceSet->insert( f );
9662       //                 setOfFaceNodeSet.insert( faceNodeSet );
9663       //               }
9664       //             }
9665       //           }
9666       //         }
9667       //       }
9668     } // Create temporary faces, if there are volumes given
9669   } // loop on sides
9670
9671   if ( faceSet1.size() != faceSet2.size() ) {
9672     // delete temporary faces: they are in reverseElements of actual nodes
9673 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9674 //    while ( tmpFaceIt->more() )
9675 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9676 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9677 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9678 //      aMesh->RemoveElement(*tmpFaceIt);
9679     MESSAGE("Diff nb of faces");
9680     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9681   }
9682
9683   // ============================================================
9684   // 2. Find nodes to merge:
9685   //              bind a node to remove to a node to put instead
9686   // ============================================================
9687
9688   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9689   if ( theFirstNode1 != theFirstNode2 )
9690     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9691   if ( theSecondNode1 != theSecondNode2 )
9692     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9693
9694   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9695   set< long > linkIdSet; // links to process
9696   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9697
9698   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9699   list< NLink > linkList[2];
9700   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9701   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9702   // loop on links in linkList; find faces by links and append links
9703   // of the found faces to linkList
9704   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9705   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
9706   {
9707     NLink link[] = { *linkIt[0], *linkIt[1] };
9708     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9709     if ( !linkIdSet.count( linkID ) )
9710       continue;
9711
9712     // by links, find faces in the face sets,
9713     // and find indices of link nodes in the found faces;
9714     // in a face set, there is only one or no face sharing a link
9715     // ---------------------------------------------------------------
9716
9717     const SMDS_MeshElement* face[] = { 0, 0 };
9718     vector<const SMDS_MeshNode*> fnodes[2];
9719     int iLinkNode[2][2];
9720     TIDSortedElemSet avoidSet;
9721     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9722       const SMDS_MeshNode* n1 = link[iSide].first;
9723       const SMDS_MeshNode* n2 = link[iSide].second;
9724       //cout << "Side " << iSide << " ";
9725       //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
9726       // find a face by two link nodes
9727       face[ iSide ] = SMESH_MeshAlgos::FindFaceInSet( n1, n2,
9728                                                       *faceSetPtr[ iSide ], avoidSet,
9729                                                       &iLinkNode[iSide][0],
9730                                                       &iLinkNode[iSide][1] );
9731       if ( face[ iSide ])
9732       {
9733         //cout << " F " << face[ iSide]->GetID() <<endl;
9734         faceSetPtr[ iSide ]->erase( face[ iSide ]);
9735         // put face nodes to fnodes
9736         if ( face[ iSide ]->IsQuadratic() )
9737         {
9738           // use interlaced nodes iterator
9739           const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
9740           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9741           SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
9742           while ( nIter->more() )
9743             fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
9744         }
9745         else
9746         {
9747           fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
9748                                   face[ iSide ]->end_nodes() );
9749         }
9750         fnodes[ iSide ].push_back( fnodes[ iSide ].front());
9751       }
9752     }
9753
9754     // check similarity of elements of the sides
9755     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
9756       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9757       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9758         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9759       }
9760       else {
9761         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9762       }
9763       break; // do not return because it's necessary to remove tmp faces
9764     }
9765
9766     // set nodes to merge
9767     // -------------------
9768
9769     if ( face[0] && face[1] )  {
9770       const int nbNodes = face[0]->NbNodes();
9771       if ( nbNodes != face[1]->NbNodes() ) {
9772         MESSAGE("Diff nb of face nodes");
9773         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9774         break; // do not return because it s necessary to remove tmp faces
9775       }
9776       bool reverse[] = { false, false }; // order of nodes in the link
9777       for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9778         // analyse link orientation in faces
9779         int i1 = iLinkNode[ iSide ][ 0 ];
9780         int i2 = iLinkNode[ iSide ][ 1 ];
9781         reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9782       }
9783       int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
9784       int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
9785       for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
9786       {
9787         nReplaceMap.insert  ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
9788                                           fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
9789       }
9790
9791       // add other links of the faces to linkList
9792       // -----------------------------------------
9793
9794       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9795         linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
9796         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9797         if ( !iter_isnew.second ) { // already in a set: no need to process
9798           linkIdSet.erase( iter_isnew.first );
9799         }
9800         else // new in set == encountered for the first time: add
9801         {
9802           const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
9803           const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
9804           linkList[0].push_back ( NLink( n1, n2 ));
9805           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9806         }
9807       }
9808     } // 2 faces found
9809
9810     if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
9811       break;
9812
9813   } // loop on link lists
9814
9815   if ( aResult == SEW_OK &&
9816        ( //linkIt[0] != linkList[0].end() ||
9817          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9818     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9819              " " << (faceSetPtr[1]->empty()));
9820     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9821   }
9822
9823   // ====================================================================
9824   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9825   // ====================================================================
9826
9827   // delete temporary faces
9828 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9829 //  while ( tmpFaceIt->more() )
9830 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9831   list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9832   for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9833     aMesh->RemoveElement(*tmpFaceIt);
9834
9835   if ( aResult != SEW_OK)
9836     return aResult;
9837
9838   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9839   // loop on nodes replacement map
9840   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9841   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9842     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9843       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9844       nodeIDsToRemove.push_back( nToRemove->GetID() );
9845       // loop on elements sharing nToRemove
9846       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9847       while ( invElemIt->more() ) {
9848         const SMDS_MeshElement* e = invElemIt->next();
9849         // get a new suite of nodes: make replacement
9850         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9851         vector< const SMDS_MeshNode*> nodes( nbNodes );
9852         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9853         while ( nIt->more() ) {
9854           const SMDS_MeshNode* n =
9855             static_cast<const SMDS_MeshNode*>( nIt->next() );
9856           nnIt = nReplaceMap.find( n );
9857           if ( nnIt != nReplaceMap.end() ) {
9858             nbReplaced++;
9859             n = (*nnIt).second;
9860           }
9861           nodes[ i++ ] = n;
9862         }
9863         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9864         //         elemIDsToRemove.push_back( e->GetID() );
9865         //       else
9866         if ( nbReplaced )
9867           {
9868             SMDSAbs_ElementType etyp = e->GetType();
9869             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
9870             if (newElem)
9871               {
9872                 myLastCreatedElems.Append(newElem);
9873                 AddToSameGroups(newElem, e, aMesh);
9874                 int aShapeId = e->getshapeId();
9875                 if ( aShapeId )
9876                   {
9877                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
9878                   }
9879               }
9880             aMesh->RemoveElement(e);
9881           }
9882       }
9883     }
9884
9885   Remove( nodeIDsToRemove, true );
9886
9887   return aResult;
9888 }
9889
9890 //================================================================================
9891 /*!
9892  * \brief Find corresponding nodes in two sets of faces
9893  * \param theSide1 - first face set
9894  * \param theSide2 - second first face
9895  * \param theFirstNode1 - a boundary node of set 1
9896  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9897  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9898  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9899  * \param nReplaceMap - output map of corresponding nodes
9900  * \return bool  - is a success or not
9901  */
9902 //================================================================================
9903
9904 #ifdef _DEBUG_
9905 //#define DEBUG_MATCHING_NODES
9906 #endif
9907
9908 SMESH_MeshEditor::Sew_Error
9909 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9910                                     set<const SMDS_MeshElement*>& theSide2,
9911                                     const SMDS_MeshNode*          theFirstNode1,
9912                                     const SMDS_MeshNode*          theFirstNode2,
9913                                     const SMDS_MeshNode*          theSecondNode1,
9914                                     const SMDS_MeshNode*          theSecondNode2,
9915                                     TNodeNodeMap &                nReplaceMap)
9916 {
9917   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9918
9919   nReplaceMap.clear();
9920   if ( theFirstNode1 != theFirstNode2 )
9921     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9922   if ( theSecondNode1 != theSecondNode2 )
9923     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9924
9925   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9926   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9927
9928   list< NLink > linkList[2];
9929   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9930   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9931
9932   // loop on links in linkList; find faces by links and append links
9933   // of the found faces to linkList
9934   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9935   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9936     NLink link[] = { *linkIt[0], *linkIt[1] };
9937     if ( linkSet.find( link[0] ) == linkSet.end() )
9938       continue;
9939
9940     // by links, find faces in the face sets,
9941     // and find indices of link nodes in the found faces;
9942     // in a face set, there is only one or no face sharing a link
9943     // ---------------------------------------------------------------
9944
9945     const SMDS_MeshElement* face[] = { 0, 0 };
9946     list<const SMDS_MeshNode*> notLinkNodes[2];
9947     //bool reverse[] = { false, false }; // order of notLinkNodes
9948     int nbNodes[2];
9949     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9950     {
9951       const SMDS_MeshNode* n1 = link[iSide].first;
9952       const SMDS_MeshNode* n2 = link[iSide].second;
9953       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9954       set< const SMDS_MeshElement* > facesOfNode1;
9955       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9956       {
9957         // during a loop of the first node, we find all faces around n1,
9958         // during a loop of the second node, we find one face sharing both n1 and n2
9959         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9960         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9961         while ( fIt->more() ) { // loop on faces sharing a node
9962           const SMDS_MeshElement* f = fIt->next();
9963           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9964               ! facesOfNode1.insert( f ).second ) // f encounters twice
9965           {
9966             if ( face[ iSide ] ) {
9967               MESSAGE( "2 faces per link " );
9968               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9969             }
9970             face[ iSide ] = f;
9971             faceSet->erase( f );
9972
9973             // get not link nodes
9974             int nbN = f->NbNodes();
9975             if ( f->IsQuadratic() )
9976               nbN /= 2;
9977             nbNodes[ iSide ] = nbN;
9978             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9979             int i1 = f->GetNodeIndex( n1 );
9980             int i2 = f->GetNodeIndex( n2 );
9981             int iEnd = nbN, iBeg = -1, iDelta = 1;
9982             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9983             if ( reverse ) {
9984               std::swap( iEnd, iBeg ); iDelta = -1;
9985             }
9986             int i = i2;
9987             while ( true ) {
9988               i += iDelta;
9989               if ( i == iEnd ) i = iBeg + iDelta;
9990               if ( i == i1 ) break;
9991               nodes.push_back ( f->GetNode( i ) );
9992             }
9993           }
9994         }
9995       }
9996     }
9997     // check similarity of elements of the sides
9998     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9999       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10000       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10001         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10002       }
10003       else {
10004         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10005       }
10006     }
10007
10008     // set nodes to merge
10009     // -------------------
10010
10011     if ( face[0] && face[1] )  {
10012       if ( nbNodes[0] != nbNodes[1] ) {
10013         MESSAGE("Diff nb of face nodes");
10014         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10015       }
10016 #ifdef DEBUG_MATCHING_NODES
10017       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10018                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10019                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10020 #endif
10021       int nbN = nbNodes[0];
10022       {
10023         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10024         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10025         for ( int i = 0 ; i < nbN - 2; ++i ) {
10026 #ifdef DEBUG_MATCHING_NODES
10027           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10028 #endif
10029           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10030         }
10031       }
10032
10033       // add other links of the face 1 to linkList
10034       // -----------------------------------------
10035
10036       const SMDS_MeshElement* f0 = face[0];
10037       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10038       for ( int i = 0; i < nbN; i++ )
10039       {
10040         const SMDS_MeshNode* n2 = f0->GetNode( i );
10041         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10042           linkSet.insert( SMESH_TLink( n1, n2 ));
10043         if ( !iter_isnew.second ) { // already in a set: no need to process
10044           linkSet.erase( iter_isnew.first );
10045         }
10046         else // new in set == encountered for the first time: add
10047         {
10048 #ifdef DEBUG_MATCHING_NODES
10049           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10050                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10051 #endif
10052           linkList[0].push_back ( NLink( n1, n2 ));
10053           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10054         }
10055         n1 = n2;
10056       }
10057     } // 2 faces found
10058   } // loop on link lists
10059
10060   return SEW_OK;
10061 }
10062
10063 //================================================================================
10064 /*!
10065  * \brief Create elements equal (on same nodes) to given ones
10066  *  \param [in] theElements - a set of elems to duplicate. If it is empty, all
10067  *              elements of the uppest dimension are duplicated.
10068  */
10069 //================================================================================
10070
10071 void SMESH_MeshEditor::DoubleElements( const TIDSortedElemSet& theElements )
10072 {
10073   CrearLastCreated();
10074   SMESHDS_Mesh* mesh = GetMeshDS();
10075
10076   // get an element type and an iterator over elements
10077
10078   SMDSAbs_ElementType type;
10079   SMDS_ElemIteratorPtr elemIt;
10080   vector< const SMDS_MeshElement* > allElems;
10081   if ( theElements.empty() )
10082   {
10083     if ( mesh->NbNodes() == 0 )
10084       return;
10085     // get most complex type
10086     SMDSAbs_ElementType types[SMDSAbs_NbElementTypes] = {
10087       SMDSAbs_Volume, SMDSAbs_Face, SMDSAbs_Edge,
10088       SMDSAbs_0DElement, SMDSAbs_Ball, SMDSAbs_Node
10089     };
10090     for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
10091       if ( mesh->GetMeshInfo().NbElements( types[i] ))
10092       {
10093         type = types[i];
10094         break;
10095       }
10096     // put all elements in the vector <allElems>
10097     allElems.reserve( mesh->GetMeshInfo().NbElements( type ));
10098     elemIt = mesh->elementsIterator( type );
10099     while ( elemIt->more() )
10100       allElems.push_back( elemIt->next());
10101     elemIt = elemSetIterator( allElems );
10102   }
10103   else
10104   {
10105     type = (*theElements.begin())->GetType();
10106     elemIt = elemSetIterator( theElements );
10107   }
10108
10109   // duplicate elements
10110
10111   if ( type == SMDSAbs_Ball )
10112   {
10113     SMDS_UnstructuredGrid* vtkGrid = mesh->getGrid();
10114     while ( elemIt->more() )
10115     {
10116       const SMDS_MeshElement* elem = elemIt->next();
10117       if ( elem->GetType() != SMDSAbs_Ball )
10118         continue;
10119       if (( elem = mesh->AddBall( elem->GetNode(0),
10120                                   vtkGrid->GetBallDiameter( elem->getVtkId() ))))
10121         myLastCreatedElems.Append( elem );
10122     }
10123   }
10124   else
10125   {
10126     vector< const SMDS_MeshNode* > nodes;
10127     while ( elemIt->more() )
10128     {
10129       const SMDS_MeshElement* elem = elemIt->next();
10130       if ( elem->GetType() != type )
10131         continue;
10132
10133       nodes.assign( elem->begin_nodes(), elem->end_nodes() );
10134
10135       if ( type == SMDSAbs_Volume  && elem->GetVtkType() == VTK_POLYHEDRON )
10136       {
10137         std::vector<int> quantities =
10138           static_cast< const SMDS_VtkVolume* >( elem )->GetQuantities();
10139         elem = mesh->AddPolyhedralVolume( nodes, quantities );
10140       }
10141       else
10142       {
10143         AddElement( nodes, type, elem->IsPoly() );
10144         elem = 0; // myLastCreatedElems is already filled
10145       }
10146       if ( elem )
10147         myLastCreatedElems.Append( elem );
10148     }
10149   }
10150 }
10151
10152 //================================================================================
10153 /*!
10154   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10155   \param theElems - the list of elements (edges or faces) to be replicated
10156   The nodes for duplication could be found from these elements
10157   \param theNodesNot - list of nodes to NOT replicate
10158   \param theAffectedElems - the list of elements (cells and edges) to which the
10159   replicated nodes should be associated to.
10160   \return TRUE if operation has been completed successfully, FALSE otherwise
10161 */
10162 //================================================================================
10163
10164 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10165                                     const TIDSortedElemSet& theNodesNot,
10166                                     const TIDSortedElemSet& theAffectedElems )
10167 {
10168   myLastCreatedElems.Clear();
10169   myLastCreatedNodes.Clear();
10170
10171   if ( theElems.size() == 0 )
10172     return false;
10173
10174   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10175   if ( !aMeshDS )
10176     return false;
10177
10178   bool res = false;
10179   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10180   // duplicate elements and nodes
10181   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10182   // replce nodes by duplications
10183   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10184   return res;
10185 }
10186
10187 //================================================================================
10188 /*!
10189   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10190   \param theMeshDS - mesh instance
10191   \param theElems - the elements replicated or modified (nodes should be changed)
10192   \param theNodesNot - nodes to NOT replicate
10193   \param theNodeNodeMap - relation of old node to new created node
10194   \param theIsDoubleElem - flag os to replicate element or modify
10195   \return TRUE if operation has been completed successfully, FALSE otherwise
10196 */
10197 //================================================================================
10198
10199 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10200                                     const TIDSortedElemSet& theElems,
10201                                     const TIDSortedElemSet& theNodesNot,
10202                                     std::map< const SMDS_MeshNode*,
10203                                     const SMDS_MeshNode* >& theNodeNodeMap,
10204                                     const bool theIsDoubleElem )
10205 {
10206   MESSAGE("doubleNodes");
10207   // iterate on through element and duplicate them (by nodes duplication)
10208   bool res = false;
10209   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10210   for ( ;  elemItr != theElems.end(); ++elemItr )
10211   {
10212     const SMDS_MeshElement* anElem = *elemItr;
10213     if (!anElem)
10214       continue;
10215
10216     bool isDuplicate = false;
10217     // duplicate nodes to duplicate element
10218     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10219     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10220     int ind = 0;
10221     while ( anIter->more() )
10222     {
10223
10224       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10225       SMDS_MeshNode* aNewNode = aCurrNode;
10226       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10227         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10228       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10229       {
10230         // duplicate node
10231         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10232         theNodeNodeMap[ aCurrNode ] = aNewNode;
10233         myLastCreatedNodes.Append( aNewNode );
10234       }
10235       isDuplicate |= (aCurrNode != aNewNode);
10236       newNodes[ ind++ ] = aNewNode;
10237     }
10238     if ( !isDuplicate )
10239       continue;
10240
10241     if ( theIsDoubleElem )
10242       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10243     else
10244       {
10245       MESSAGE("ChangeElementNodes");
10246       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10247       }
10248     res = true;
10249   }
10250   return res;
10251 }
10252
10253 //================================================================================
10254 /*!
10255   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10256   \param theNodes - identifiers of nodes to be doubled
10257   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10258          nodes. If list of element identifiers is empty then nodes are doubled but
10259          they not assigned to elements
10260   \return TRUE if operation has been completed successfully, FALSE otherwise
10261 */
10262 //================================================================================
10263
10264 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10265                                     const std::list< int >& theListOfModifiedElems )
10266 {
10267   MESSAGE("DoubleNodes");
10268   myLastCreatedElems.Clear();
10269   myLastCreatedNodes.Clear();
10270
10271   if ( theListOfNodes.size() == 0 )
10272     return false;
10273
10274   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10275   if ( !aMeshDS )
10276     return false;
10277
10278   // iterate through nodes and duplicate them
10279
10280   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10281
10282   std::list< int >::const_iterator aNodeIter;
10283   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10284   {
10285     int aCurr = *aNodeIter;
10286     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10287     if ( !aNode )
10288       continue;
10289
10290     // duplicate node
10291
10292     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10293     if ( aNewNode )
10294     {
10295       anOldNodeToNewNode[ aNode ] = aNewNode;
10296       myLastCreatedNodes.Append( aNewNode );
10297     }
10298   }
10299
10300   // Create map of new nodes for modified elements
10301
10302   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10303
10304   std::list< int >::const_iterator anElemIter;
10305   for ( anElemIter = theListOfModifiedElems.begin();
10306         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10307   {
10308     int aCurr = *anElemIter;
10309     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10310     if ( !anElem )
10311       continue;
10312
10313     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10314
10315     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10316     int ind = 0;
10317     while ( anIter->more() )
10318     {
10319       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10320       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10321       {
10322         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10323         aNodeArr[ ind++ ] = aNewNode;
10324       }
10325       else
10326         aNodeArr[ ind++ ] = aCurrNode;
10327     }
10328     anElemToNodes[ anElem ] = aNodeArr;
10329   }
10330
10331   // Change nodes of elements
10332
10333   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10334     anElemToNodesIter = anElemToNodes.begin();
10335   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10336   {
10337     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10338     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10339     if ( anElem )
10340       {
10341       MESSAGE("ChangeElementNodes");
10342       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10343       }
10344   }
10345
10346   return true;
10347 }
10348
10349 namespace {
10350
10351   //================================================================================
10352   /*!
10353   \brief Check if element located inside shape
10354   \return TRUE if IN or ON shape, FALSE otherwise
10355   */
10356   //================================================================================
10357
10358   template<class Classifier>
10359   bool isInside(const SMDS_MeshElement* theElem,
10360                 Classifier&             theClassifier,
10361                 const double            theTol)
10362   {
10363     gp_XYZ centerXYZ (0, 0, 0);
10364     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10365     while (aNodeItr->more())
10366       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10367
10368     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10369     theClassifier.Perform(aPnt, theTol);
10370     TopAbs_State aState = theClassifier.State();
10371     return (aState == TopAbs_IN || aState == TopAbs_ON );
10372   }
10373
10374   //================================================================================
10375   /*!
10376    * \brief Classifier of the 3D point on the TopoDS_Face
10377    *        with interaface suitable for isInside()
10378    */
10379   //================================================================================
10380
10381   struct _FaceClassifier
10382   {
10383     Extrema_ExtPS       _extremum;
10384     BRepAdaptor_Surface _surface;
10385     TopAbs_State        _state;
10386
10387     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10388     {
10389       _extremum.Initialize( _surface,
10390                             _surface.FirstUParameter(), _surface.LastUParameter(),
10391                             _surface.FirstVParameter(), _surface.LastVParameter(),
10392                             _surface.Tolerance(), _surface.Tolerance() );
10393     }
10394     void Perform(const gp_Pnt& aPnt, double theTol)
10395     {
10396       theTol *= theTol;
10397       _state = TopAbs_OUT;
10398       _extremum.Perform(aPnt);
10399       if ( _extremum.IsDone() )
10400         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10401           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10402     }
10403     TopAbs_State State() const
10404     {
10405       return _state;
10406     }
10407   };
10408 }
10409
10410 //================================================================================
10411 /*!
10412   \brief Identify the elements that will be affected by node duplication (actual duplication is not performed).
10413   This method is the first step of DoubleNodeElemGroupsInRegion.
10414   \param theElems - list of groups of elements (edges or faces) to be replicated
10415   \param theNodesNot - list of groups of nodes not to replicated
10416   \param theShape - shape to detect affected elements (element which geometric center
10417          located on or inside shape). If the shape is null, detection is done on faces orientations
10418          (select elements with a gravity center on the side given by faces normals).
10419          This mode (null shape) is faster, but works only when theElems are faces, with coherents orientations.
10420          The replicated nodes should be associated to affected elements.
10421   \return groups of affected elements
10422   \sa DoubleNodeElemGroupsInRegion()
10423  */
10424 //================================================================================
10425
10426 bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
10427                                                    const TIDSortedElemSet& theNodesNot,
10428                                                    const TopoDS_Shape&     theShape,
10429                                                    TIDSortedElemSet&       theAffectedElems)
10430 {
10431   if ( theShape.IsNull() )
10432   {
10433     std::set<const SMDS_MeshNode*> alreadyCheckedNodes;
10434     std::set<const SMDS_MeshElement*> alreadyCheckedElems;
10435     std::set<const SMDS_MeshElement*> edgesToCheck;
10436     alreadyCheckedNodes.clear();
10437     alreadyCheckedElems.clear();
10438     edgesToCheck.clear();
10439
10440     // --- iterates on elements to be replicated and get elements by back references from their nodes
10441
10442     TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10443     int ielem;
10444     for ( ielem=1;  elemItr != theElems.end(); ++elemItr )
10445     {
10446       SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10447       if (!anElem || (anElem->GetType() != SMDSAbs_Face))
10448         continue;
10449       gp_XYZ normal;
10450       SMESH_MeshAlgos::FaceNormal( anElem, normal, /*normalized=*/true );
10451       MESSAGE("element " << ielem++ <<  " normal " << normal.X() << " " << normal.Y() << " " << normal.Z());
10452       std::set<const SMDS_MeshNode*> nodesElem;
10453       nodesElem.clear();
10454       SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10455       while ( nodeItr->more() )
10456       {
10457         const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10458         nodesElem.insert(aNode);
10459       }
10460       std::set<const SMDS_MeshNode*>::iterator nodit = nodesElem.begin();
10461       for (; nodit != nodesElem.end(); nodit++)
10462       {
10463         MESSAGE("  noeud ");
10464         const SMDS_MeshNode* aNode = *nodit;
10465         if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10466           continue;
10467         if (alreadyCheckedNodes.find(aNode) != alreadyCheckedNodes.end())
10468           continue;
10469         alreadyCheckedNodes.insert(aNode);
10470         SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10471         while ( backElemItr->more() )
10472         {
10473           MESSAGE("    backelem ");
10474           const SMDS_MeshElement* curElem = backElemItr->next();
10475           if (alreadyCheckedElems.find(curElem) != alreadyCheckedElems.end())
10476             continue;
10477           if (theElems.find(curElem) != theElems.end())
10478             continue;
10479           alreadyCheckedElems.insert(curElem);
10480           double x=0, y=0, z=0;
10481           int nb = 0;
10482           SMDS_ElemIteratorPtr nodeItr2 = curElem->nodesIterator();
10483           while ( nodeItr2->more() )
10484           {
10485             const SMDS_MeshNode* anotherNode = cast2Node(nodeItr2->next());
10486             x += anotherNode->X();
10487             y += anotherNode->Y();
10488             z += anotherNode->Z();
10489             nb++;
10490           }
10491           gp_XYZ p;
10492           p.SetCoord( x/nb -aNode->X(),
10493                       y/nb -aNode->Y(),
10494                       z/nb -aNode->Z() );
10495           MESSAGE("      check " << p.X() << " " << p.Y() << " " << p.Z());
10496           if (normal*p > 0)
10497           {
10498             MESSAGE("    --- inserted")
10499             theAffectedElems.insert( curElem );
10500           }
10501           else if (curElem->GetType() == SMDSAbs_Edge)
10502             edgesToCheck.insert(curElem);
10503         }
10504       }
10505     }
10506     // --- add also edges lying on the set of faces (all nodes in alreadyCheckedNodes)
10507     std::set<const SMDS_MeshElement*>::iterator eit = edgesToCheck.begin();
10508     for( ; eit != edgesToCheck.end(); eit++)
10509     {
10510       bool onside = true;
10511       const SMDS_MeshElement* anEdge = *eit;
10512       SMDS_ElemIteratorPtr nodeItr = anEdge->nodesIterator();
10513       while ( nodeItr->more() )
10514       {
10515         const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10516         if (alreadyCheckedNodes.find(aNode) == alreadyCheckedNodes.end())
10517         {
10518           onside = false;
10519           break;
10520         }
10521       }
10522       if (onside)
10523       {
10524         MESSAGE("    --- edge onside inserted")
10525         theAffectedElems.insert(anEdge);
10526       }
10527     }
10528   }
10529   else
10530   {
10531     const double aTol = Precision::Confusion();
10532     auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10533     auto_ptr<_FaceClassifier>              aFaceClassifier;
10534     if ( theShape.ShapeType() == TopAbs_SOLID )
10535     {
10536       bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10537       bsc3d->PerformInfinitePoint(aTol);
10538     }
10539     else if (theShape.ShapeType() == TopAbs_FACE )
10540     {
10541       aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10542     }
10543
10544     // iterates on indicated elements and get elements by back references from their nodes
10545     TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10546     int ielem;
10547     for ( ielem = 1;  elemItr != theElems.end(); ++elemItr )
10548     {
10549       MESSAGE("element " << ielem++);
10550       SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10551       if (!anElem)
10552         continue;
10553       SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10554       while ( nodeItr->more() )
10555       {
10556         MESSAGE("  noeud ");
10557         const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10558         if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10559           continue;
10560         SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10561         while ( backElemItr->more() )
10562         {
10563           MESSAGE("    backelem ");
10564           const SMDS_MeshElement* curElem = backElemItr->next();
10565           if ( curElem && theElems.find(curElem) == theElems.end() &&
10566               ( bsc3d.get() ?
10567                 isInside( curElem, *bsc3d, aTol ) :
10568                 isInside( curElem, *aFaceClassifier, aTol )))
10569             theAffectedElems.insert( curElem );
10570         }
10571       }
10572     }
10573   }
10574   return true;
10575 }
10576
10577 //================================================================================
10578 /*!
10579   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10580   \param theElems - group of of elements (edges or faces) to be replicated
10581   \param theNodesNot - group of nodes not to replicate
10582   \param theShape - shape to detect affected elements (element which geometric center
10583   located on or inside shape).
10584   The replicated nodes should be associated to affected elements.
10585   \return TRUE if operation has been completed successfully, FALSE otherwise
10586 */
10587 //================================================================================
10588
10589 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10590                                             const TIDSortedElemSet& theNodesNot,
10591                                             const TopoDS_Shape&     theShape )
10592 {
10593   if ( theShape.IsNull() )
10594     return false;
10595
10596   const double aTol = Precision::Confusion();
10597   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10598   auto_ptr<_FaceClassifier>              aFaceClassifier;
10599   if ( theShape.ShapeType() == TopAbs_SOLID )
10600   {
10601     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10602     bsc3d->PerformInfinitePoint(aTol);
10603   }
10604   else if (theShape.ShapeType() == TopAbs_FACE )
10605   {
10606     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10607   }
10608
10609   // iterates on indicated elements and get elements by back references from their nodes
10610   TIDSortedElemSet anAffected;
10611   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10612   for ( ;  elemItr != theElems.end(); ++elemItr )
10613   {
10614     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10615     if (!anElem)
10616       continue;
10617
10618     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10619     while ( nodeItr->more() )
10620     {
10621       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10622       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10623         continue;
10624       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10625       while ( backElemItr->more() )
10626       {
10627         const SMDS_MeshElement* curElem = backElemItr->next();
10628         if ( curElem && theElems.find(curElem) == theElems.end() &&
10629              ( bsc3d.get() ?
10630                isInside( curElem, *bsc3d, aTol ) :
10631                isInside( curElem, *aFaceClassifier, aTol )))
10632           anAffected.insert( curElem );
10633       }
10634     }
10635   }
10636   return DoubleNodes( theElems, theNodesNot, anAffected );
10637 }
10638
10639 /*!
10640  *  \brief compute an oriented angle between two planes defined by four points.
10641  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10642  *  @param p0 base of the rotation axe
10643  *  @param p1 extremity of the rotation axe
10644  *  @param g1 belongs to the first plane
10645  *  @param g2 belongs to the second plane
10646  */
10647 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10648 {
10649 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10650 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10651 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10652 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10653   gp_Vec vref(p0, p1);
10654   gp_Vec v1(p0, g1);
10655   gp_Vec v2(p0, g2);
10656   gp_Vec n1 = vref.Crossed(v1);
10657   gp_Vec n2 = vref.Crossed(v2);
10658   try {
10659     return n2.AngleWithRef(n1, vref);
10660   }
10661   catch ( Standard_Failure ) {
10662   }
10663   return Max( v1.Magnitude(), v2.Magnitude() );
10664 }
10665
10666 /*!
10667  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10668  *  The list of groups must contain at least two groups. The groups have to be disjoint: no common element into two different groups.
10669  * The nodes of the internal faces at the boundaries of the groups are doubled. Optionally, the internal faces are replaced by flat elements.
10670  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
10671  * The flat elements are stored in groups of volumes. These groups are named according to the position of the group in the list:
10672  * 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.
10673  * 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.
10674  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
10675  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
10676  * \param theElems - list of groups of volumes, where a group of volume is a set of
10677  *        SMDS_MeshElements sorted by Id.
10678  * \param createJointElems - if TRUE, create the elements
10679  * \param onAllBoundaries - if TRUE, the nodes and elements are also created on
10680  *        the boundary between \a theDomains and the rest mesh
10681  * \return TRUE if operation has been completed successfully, FALSE otherwise
10682  */
10683 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10684                                                      bool                                 createJointElems,
10685                                                      bool                                 onAllBoundaries)
10686 {
10687   MESSAGE("----------------------------------------------");
10688   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10689   MESSAGE("----------------------------------------------");
10690
10691   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10692   meshDS->BuildDownWardConnectivity(true);
10693   CHRONO(50);
10694   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10695
10696   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10697   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10698   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10699
10700   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10701   std::map<int,int>celldom; // cell vtkId --> domain
10702   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10703   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10704   faceDomains.clear();
10705   celldom.clear();
10706   cellDomains.clear();
10707   nodeDomains.clear();
10708   std::map<int,int> emptyMap;
10709   std::set<int> emptySet;
10710   emptyMap.clear();
10711
10712   MESSAGE(".. Number of domains :"<<theElems.size());
10713
10714   TIDSortedElemSet theRestDomElems;
10715   const int iRestDom  = -1;
10716   const int idom0     = onAllBoundaries ? iRestDom : 0;
10717   const int nbDomains = theElems.size();
10718
10719   // Check if the domains do not share an element
10720   for (int idom = 0; idom < nbDomains-1; idom++)
10721     {
10722 //       MESSAGE("... Check of domain #" << idom);
10723       const TIDSortedElemSet& domain = theElems[idom];
10724       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10725       for (; elemItr != domain.end(); ++elemItr)
10726         {
10727           const SMDS_MeshElement* anElem = *elemItr;
10728           int idombisdeb = idom + 1 ;
10729           for (int idombis = idombisdeb; idombis < theElems.size(); idombis++) // check if the element belongs to a domain further in the list
10730           {
10731             const TIDSortedElemSet& domainbis = theElems[idombis];
10732             if ( domainbis.count(anElem) )
10733             {
10734               MESSAGE(".... Domain #" << idom);
10735               MESSAGE(".... Domain #" << idombis);
10736               throw SALOME_Exception("The domains are not disjoint.");
10737               return false ;
10738             }
10739           }
10740         }
10741     }
10742
10743   for (int idom = 0; idom < nbDomains; idom++)
10744     {
10745
10746       // --- build a map (face to duplicate --> volume to modify)
10747       //     with all the faces shared by 2 domains (group of elements)
10748       //     and corresponding volume of this domain, for each shared face.
10749       //     a volume has a face shared by 2 domains if it has a neighbor which is not in his domain.
10750
10751       MESSAGE("... Neighbors of domain #" << idom);
10752       const TIDSortedElemSet& domain = theElems[idom];
10753       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10754       for (; elemItr != domain.end(); ++elemItr)
10755         {
10756           const SMDS_MeshElement* anElem = *elemItr;
10757           if (!anElem)
10758             continue;
10759           int vtkId = anElem->getVtkId();
10760           //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
10761           int neighborsVtkIds[NBMAXNEIGHBORS];
10762           int downIds[NBMAXNEIGHBORS];
10763           unsigned char downTypes[NBMAXNEIGHBORS];
10764           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10765           for (int n = 0; n < nbNeighbors; n++)
10766             {
10767               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10768               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10769               if (elem && ! domain.count(elem)) // neighbor is in another domain : face is shared
10770                 {
10771                   bool ok = false ;
10772                   for (int idombis = 0; idombis < theElems.size() && !ok; idombis++) // check if the neighbor belongs to another domain of the list
10773                   {
10774                     // MESSAGE("Domain " << idombis);
10775                     const TIDSortedElemSet& domainbis = theElems[idombis];
10776                     if ( domainbis.count(elem)) ok = true ; // neighbor is in a correct domain : face is kept
10777                   }
10778                   if ( ok || onAllBoundaries ) // the characteristics of the face is stored
10779                   {
10780                     DownIdType face(downIds[n], downTypes[n]);
10781                     if (!faceDomains[face].count(idom))
10782                       {
10783                         faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10784                         celldom[vtkId] = idom;
10785                         //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
10786                       }
10787                     if ( !ok )
10788                     {
10789                       theRestDomElems.insert( elem );
10790                       faceDomains[face][iRestDom] = neighborsVtkIds[n];
10791                       celldom[neighborsVtkIds[n]] = iRestDom;
10792                     }
10793                   }
10794                 }
10795             }
10796         }
10797     }
10798
10799   //MESSAGE("Number of shared faces " << faceDomains.size());
10800   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10801
10802   // --- explore the shared faces domain by domain,
10803   //     explore the nodes of the face and see if they belong to a cell in the domain,
10804   //     which has only a node or an edge on the border (not a shared face)
10805
10806   for (int idomain = idom0; idomain < nbDomains; idomain++)
10807     {
10808       //MESSAGE("Domain " << idomain);
10809       const TIDSortedElemSet& domain = (idomain == iRestDom) ? theRestDomElems : theElems[idomain];
10810       itface = faceDomains.begin();
10811       for (; itface != faceDomains.end(); ++itface)
10812         {
10813           const std::map<int, int>& domvol = itface->second;
10814           if (!domvol.count(idomain))
10815             continue;
10816           DownIdType face = itface->first;
10817           //MESSAGE(" --- face " << face.cellId);
10818           std::set<int> oldNodes;
10819           oldNodes.clear();
10820           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10821           std::set<int>::iterator itn = oldNodes.begin();
10822           for (; itn != oldNodes.end(); ++itn)
10823             {
10824               int oldId = *itn;
10825               //MESSAGE("     node " << oldId);
10826               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10827               for (int i=0; i<l.ncells; i++)
10828                 {
10829                   int vtkId = l.cells[i];
10830                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10831                   if (!domain.count(anElem))
10832                     continue;
10833                   int vtkType = grid->GetCellType(vtkId);
10834                   int downId = grid->CellIdToDownId(vtkId);
10835                   if (downId < 0)
10836                     {
10837                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
10838                       continue; // not OK at this stage of the algorithm:
10839                                 //no cells created after BuildDownWardConnectivity
10840                     }
10841                   DownIdType aCell(downId, vtkType);
10842                   cellDomains[aCell][idomain] = vtkId;
10843                   celldom[vtkId] = idomain;
10844                   //MESSAGE("       cell " << vtkId << " domain " << idomain);
10845                 }
10846             }
10847         }
10848     }
10849
10850   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10851   //     for each shared face, get the nodes
10852   //     for each node, for each domain of the face, create a clone of the node
10853
10854   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10855   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10856   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
10857
10858   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10859   std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
10860   std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
10861
10862   MESSAGE(".. Duplication of the nodes");
10863   for (int idomain = idom0; idomain < nbDomains; idomain++)
10864     {
10865       itface = faceDomains.begin();
10866       for (; itface != faceDomains.end(); ++itface)
10867         {
10868           const std::map<int, int>& domvol = itface->second;
10869           if (!domvol.count(idomain))
10870             continue;
10871           DownIdType face = itface->first;
10872           //MESSAGE(" --- face " << face.cellId);
10873           std::set<int> oldNodes;
10874           oldNodes.clear();
10875           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10876           std::set<int>::iterator itn = oldNodes.begin();
10877           for (; itn != oldNodes.end(); ++itn)
10878             {
10879               int oldId = *itn;
10880               if (nodeDomains[oldId].empty())
10881                 {
10882                   nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
10883                   //MESSAGE("-+-+-b     oldNode " << oldId << " domain " << idomain);
10884                 }
10885               std::map<int, int>::const_iterator itdom = domvol.begin();
10886               for (; itdom != domvol.end(); ++itdom)
10887                 {
10888                   int idom = itdom->first;
10889                   //MESSAGE("         domain " << idom);
10890                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
10891                     {
10892                       if (nodeDomains[oldId].size() >= 2) // a multiple node
10893                         {
10894                           vector<int> orderedDoms;
10895                           //MESSAGE("multiple node " << oldId);
10896                           if (mutipleNodes.count(oldId))
10897                             orderedDoms = mutipleNodes[oldId];
10898                           else
10899                             {
10900                               map<int,int>::iterator it = nodeDomains[oldId].begin();
10901                               for (; it != nodeDomains[oldId].end(); ++it)
10902                                 orderedDoms.push_back(it->first);
10903                             }
10904                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
10905                           //stringstream txt;
10906                           //for (int i=0; i<orderedDoms.size(); i++)
10907                           //  txt << orderedDoms[i] << " ";
10908                           //MESSAGE("orderedDoms " << txt.str());
10909                           mutipleNodes[oldId] = orderedDoms;
10910                         }
10911                       double *coords = grid->GetPoint(oldId);
10912                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10913                       int newId = newNode->getVtkId();
10914                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
10915                       //MESSAGE("-+-+-c     oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
10916                     }
10917                 }
10918             }
10919         }
10920     }
10921
10922   MESSAGE(".. Creation of elements");
10923   for (int idomain = idom0; idomain < nbDomains; idomain++)
10924     {
10925       itface = faceDomains.begin();
10926       for (; itface != faceDomains.end(); ++itface)
10927         {
10928           std::map<int, int> domvol = itface->second;
10929           if (!domvol.count(idomain))
10930             continue;
10931           DownIdType face = itface->first;
10932           //MESSAGE(" --- face " << face.cellId);
10933           std::set<int> oldNodes;
10934           oldNodes.clear();
10935           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10936           int nbMultipleNodes = 0;
10937           std::set<int>::iterator itn = oldNodes.begin();
10938           for (; itn != oldNodes.end(); ++itn)
10939             {
10940               int oldId = *itn;
10941               if (mutipleNodes.count(oldId))
10942                 nbMultipleNodes++;
10943             }
10944           if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains
10945             {
10946               //MESSAGE("multiple Nodes detected on a shared face");
10947               int downId = itface->first.cellId;
10948               unsigned char cellType = itface->first.cellType;
10949               // --- shared edge or shared face ?
10950               if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
10951                 {
10952                   int nodes[3];
10953                   int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
10954                   for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
10955                     if (mutipleNodes.count(nodes[i]))
10956                       if (!mutipleNodesToFace.count(nodes[i]))
10957                         mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
10958                 }
10959               else // shared face (between two volumes)
10960                 {
10961                   int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
10962                   const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
10963                   const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
10964                   for (int ie =0; ie < nbEdges; ie++)
10965                     {
10966                       int nodes[3];
10967                       int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
10968                       if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
10969                         {
10970                           vector<int> vn0 = mutipleNodes[nodes[0]];
10971                           vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
10972                           vector<int> doms;
10973                           for (int i0 = 0; i0 < vn0.size(); i0++)
10974                             for (int i1 = 0; i1 < vn1.size(); i1++)
10975                               if (vn0[i0] == vn1[i1])
10976                                 doms.push_back(vn0[i0]);
10977                           if (doms.size() >2)
10978                             {
10979                               //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
10980                               double *coords = grid->GetPoint(nodes[0]);
10981                               gp_Pnt p0(coords[0], coords[1], coords[2]);
10982                               coords = grid->GetPoint(nodes[nbNodes - 1]);
10983                               gp_Pnt p1(coords[0], coords[1], coords[2]);
10984                               gp_Pnt gref;
10985                               int vtkVolIds[1000];  // an edge can belong to a lot of volumes
10986                               map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
10987                               map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
10988                               int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
10989                               for (int id=0; id < doms.size(); id++)
10990                                 {
10991                                   int idom = doms[id];
10992                                   const TIDSortedElemSet& domain = (idom == iRestDom) ? theRestDomElems : theElems[idom];
10993                                   for (int ivol=0; ivol<nbvol; ivol++)
10994                                     {
10995                                       int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
10996                                       SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
10997                                       if (domain.count(elem))
10998                                         {
10999                                           SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11000                                           domvol[idom] = svol;
11001                                           //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11002                                           double values[3];
11003                                           vtkIdType npts = 0;
11004                                           vtkIdType* pts = 0;
11005                                           grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11006                                           SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11007                                           if (id ==0)
11008                                             {
11009                                               gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11010                                               angleDom[idom] = 0;
11011                                             }
11012                                           else
11013                                             {
11014                                               gp_Pnt g(values[0], values[1], values[2]);
11015                                               angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11016                                               //MESSAGE("  angle=" << angleDom[idom]);
11017                                             }
11018                                           break;
11019                                         }
11020                                     }
11021                                 }
11022                               map<double, int> sortedDom; // sort domains by angle
11023                               for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11024                                 sortedDom[ia->second] = ia->first;
11025                               vector<int> vnodes;
11026                               vector<int> vdom;
11027                               for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11028                                 {
11029                                   vdom.push_back(ib->second);
11030                                   //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11031                                 }
11032                               for (int ino = 0; ino < nbNodes; ino++)
11033                                 vnodes.push_back(nodes[ino]);
11034                               edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11035                             }
11036                         }
11037                     }
11038                 }
11039             }
11040         }
11041     }
11042
11043   // --- iterate on shared faces (volumes to modify, face to extrude)
11044   //     get node id's of the face (id SMDS = id VTK)
11045   //     create flat element with old and new nodes if requested
11046
11047   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11048   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11049
11050   std::map<int, std::map<long,int> > nodeQuadDomains;
11051   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11052
11053   MESSAGE(".. Creation of elements: simple junction");
11054   if (createJointElems)
11055     {
11056       int idg;
11057       string joints2DName = "joints2D";
11058       mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg);
11059       SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
11060       string joints3DName = "joints3D";
11061       mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg);
11062       SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
11063
11064       itface = faceDomains.begin();
11065       for (; itface != faceDomains.end(); ++itface)
11066         {
11067           DownIdType face = itface->first;
11068           std::set<int> oldNodes;
11069           std::set<int>::iterator itn;
11070           oldNodes.clear();
11071           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11072
11073           std::map<int, int> domvol = itface->second;
11074           std::map<int, int>::iterator itdom = domvol.begin();
11075           int dom1 = itdom->first;
11076           int vtkVolId = itdom->second;
11077           itdom++;
11078           int dom2 = itdom->first;
11079           SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11080                                                              nodeQuadDomains);
11081           stringstream grpname;
11082           grpname << "j_";
11083           if (dom1 < dom2)
11084             grpname << dom1 << "_" << dom2;
11085           else
11086             grpname << dom2 << "_" << dom1;
11087           string namegrp = grpname.str();
11088           if (!mapOfJunctionGroups.count(namegrp))
11089             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
11090           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11091           if (sgrp)
11092             sgrp->Add(vol->GetID());
11093           if (vol->GetType() == SMDSAbs_Volume)
11094             joints3DGrp->Add(vol->GetID());
11095           else if (vol->GetType() == SMDSAbs_Face)
11096             joints2DGrp->Add(vol->GetID());
11097         }
11098     }
11099
11100   // --- create volumes on multiple domain intersection if requested
11101   //     iterate on mutipleNodesToFace
11102   //     iterate on edgesMultiDomains
11103
11104   MESSAGE(".. Creation of elements: multiple junction");
11105   if (createJointElems)
11106     {
11107       // --- iterate on mutipleNodesToFace
11108
11109       std::map<int, std::vector<int> >::iterator itn =  mutipleNodesToFace.begin();
11110       for (; itn != mutipleNodesToFace.end(); ++itn)
11111         {
11112           int node = itn->first;
11113           vector<int> orderDom = itn->second;
11114           vector<vtkIdType> orderedNodes;
11115           for (int idom = 0; idom <orderDom.size(); idom++)
11116             orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
11117             SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
11118
11119             stringstream grpname;
11120             grpname << "m2j_";
11121             grpname << 0 << "_" << 0;
11122             int idg;
11123             string namegrp = grpname.str();
11124             if (!mapOfJunctionGroups.count(namegrp))
11125               mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
11126             SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11127             if (sgrp)
11128               sgrp->Add(face->GetID());
11129         }
11130
11131       // --- iterate on edgesMultiDomains
11132
11133       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11134       for (; ite != edgesMultiDomains.end(); ++ite)
11135         {
11136           vector<int> nodes = ite->first;
11137           vector<int> orderDom = ite->second;
11138           vector<vtkIdType> orderedNodes;
11139           if (nodes.size() == 2)
11140             {
11141               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11142               for (int ino=0; ino < nodes.size(); ino++)
11143                 if (orderDom.size() == 3)
11144                   for (int idom = 0; idom <orderDom.size(); idom++)
11145                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11146                 else
11147                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11148                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11149               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11150
11151               int idg;
11152               string namegrp = "jointsMultiples";
11153               if (!mapOfJunctionGroups.count(namegrp))
11154                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11155               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11156               if (sgrp)
11157                 sgrp->Add(vol->GetID());
11158             }
11159           else
11160             {
11161               INFOS("Quadratic multiple joints not implemented");
11162               // TODO quadratic nodes
11163             }
11164         }
11165     }
11166
11167   // --- list the explicit faces and edges of the mesh that need to be modified,
11168   //     i.e. faces and edges built with one or more duplicated nodes.
11169   //     associate these faces or edges to their corresponding domain.
11170   //     only the first domain found is kept when a face or edge is shared
11171
11172   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11173   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11174   faceOrEdgeDom.clear();
11175   feDom.clear();
11176
11177   MESSAGE(".. Modification of elements");
11178   for (int idomain = idom0; idomain < nbDomains; idomain++)
11179     {
11180       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11181       for (; itnod != nodeDomains.end(); ++itnod)
11182         {
11183           int oldId = itnod->first;
11184           //MESSAGE("     node " << oldId);
11185           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11186           for (int i = 0; i < l.ncells; i++)
11187             {
11188               int vtkId = l.cells[i];
11189               int vtkType = grid->GetCellType(vtkId);
11190               int downId = grid->CellIdToDownId(vtkId);
11191               if (downId < 0)
11192                 continue; // new cells: not to be modified
11193               DownIdType aCell(downId, vtkType);
11194               int volParents[1000];
11195               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11196               for (int j = 0; j < nbvol; j++)
11197                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11198                   if (!feDom.count(vtkId))
11199                     {
11200                       feDom[vtkId] = idomain;
11201                       faceOrEdgeDom[aCell] = emptyMap;
11202                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11203                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11204                       //        << " type " << vtkType << " downId " << downId);
11205                     }
11206             }
11207         }
11208     }
11209
11210   // --- iterate on shared faces (volumes to modify, face to extrude)
11211   //     get node id's of the face
11212   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11213
11214   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11215   for (int m=0; m<3; m++)
11216     {
11217       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11218       itface = (*amap).begin();
11219       for (; itface != (*amap).end(); ++itface)
11220         {
11221           DownIdType face = itface->first;
11222           std::set<int> oldNodes;
11223           std::set<int>::iterator itn;
11224           oldNodes.clear();
11225           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11226           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11227           std::map<int, int> localClonedNodeIds;
11228
11229           std::map<int, int> domvol = itface->second;
11230           std::map<int, int>::iterator itdom = domvol.begin();
11231           for (; itdom != domvol.end(); ++itdom)
11232             {
11233               int idom = itdom->first;
11234               int vtkVolId = itdom->second;
11235               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11236               localClonedNodeIds.clear();
11237               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11238                 {
11239                   int oldId = *itn;
11240                   if (nodeDomains[oldId].count(idom))
11241                     {
11242                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11243                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11244                     }
11245                 }
11246               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11247             }
11248         }
11249     }
11250
11251   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11252   grid->BuildLinks();
11253
11254   CHRONOSTOP(50);
11255   counters::stats();
11256   return true;
11257 }
11258
11259 /*!
11260  * \brief Double nodes on some external faces and create flat elements.
11261  * Flat elements are mainly used by some types of mechanic calculations.
11262  *
11263  * Each group of the list must be constituted of faces.
11264  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11265  * @param theElems - list of groups of faces, where a group of faces is a set of
11266  * SMDS_MeshElements sorted by Id.
11267  * @return TRUE if operation has been completed successfully, FALSE otherwise
11268  */
11269 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11270 {
11271   MESSAGE("-------------------------------------------------");
11272   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11273   MESSAGE("-------------------------------------------------");
11274
11275   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11276
11277   // --- For each group of faces
11278   //     duplicate the nodes, create a flat element based on the face
11279   //     replace the nodes of the faces by their clones
11280
11281   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11282   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11283   clonedNodes.clear();
11284   intermediateNodes.clear();
11285   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11286   mapOfJunctionGroups.clear();
11287
11288   for (int idom = 0; idom < theElems.size(); idom++)
11289     {
11290       const TIDSortedElemSet& domain = theElems[idom];
11291       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11292       for (; elemItr != domain.end(); ++elemItr)
11293         {
11294           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11295           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11296           if (!aFace)
11297             continue;
11298           // MESSAGE("aFace=" << aFace->GetID());
11299           bool isQuad = aFace->IsQuadratic();
11300           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11301
11302           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11303
11304           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11305           while (nodeIt->more())
11306             {
11307               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11308               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11309               if (isMedium)
11310                 ln2.push_back(node);
11311               else
11312                 ln0.push_back(node);
11313
11314               const SMDS_MeshNode* clone = 0;
11315               if (!clonedNodes.count(node))
11316                 {
11317                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11318                   clonedNodes[node] = clone;
11319                 }
11320               else
11321                 clone = clonedNodes[node];
11322
11323               if (isMedium)
11324                 ln3.push_back(clone);
11325               else
11326                 ln1.push_back(clone);
11327
11328               const SMDS_MeshNode* inter = 0;
11329               if (isQuad && (!isMedium))
11330                 {
11331                   if (!intermediateNodes.count(node))
11332                     {
11333                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11334                       intermediateNodes[node] = inter;
11335                     }
11336                   else
11337                     inter = intermediateNodes[node];
11338                   ln4.push_back(inter);
11339                 }
11340             }
11341
11342           // --- extrude the face
11343
11344           vector<const SMDS_MeshNode*> ln;
11345           SMDS_MeshVolume* vol = 0;
11346           vtkIdType aType = aFace->GetVtkType();
11347           switch (aType)
11348           {
11349             case VTK_TRIANGLE:
11350               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11351               // MESSAGE("vol prism " << vol->GetID());
11352               ln.push_back(ln1[0]);
11353               ln.push_back(ln1[1]);
11354               ln.push_back(ln1[2]);
11355               break;
11356             case VTK_QUAD:
11357               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11358               // MESSAGE("vol hexa " << vol->GetID());
11359               ln.push_back(ln1[0]);
11360               ln.push_back(ln1[1]);
11361               ln.push_back(ln1[2]);
11362               ln.push_back(ln1[3]);
11363               break;
11364             case VTK_QUADRATIC_TRIANGLE:
11365               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11366                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11367               // MESSAGE("vol quad prism " << vol->GetID());
11368               ln.push_back(ln1[0]);
11369               ln.push_back(ln1[1]);
11370               ln.push_back(ln1[2]);
11371               ln.push_back(ln3[0]);
11372               ln.push_back(ln3[1]);
11373               ln.push_back(ln3[2]);
11374               break;
11375             case VTK_QUADRATIC_QUAD:
11376 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11377 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11378 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11379               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11380                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11381                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11382               // MESSAGE("vol quad hexa " << vol->GetID());
11383               ln.push_back(ln1[0]);
11384               ln.push_back(ln1[1]);
11385               ln.push_back(ln1[2]);
11386               ln.push_back(ln1[3]);
11387               ln.push_back(ln3[0]);
11388               ln.push_back(ln3[1]);
11389               ln.push_back(ln3[2]);
11390               ln.push_back(ln3[3]);
11391               break;
11392             case VTK_POLYGON:
11393               break;
11394             default:
11395               break;
11396           }
11397
11398           if (vol)
11399             {
11400               stringstream grpname;
11401               grpname << "jf_";
11402               grpname << idom;
11403               int idg;
11404               string namegrp = grpname.str();
11405               if (!mapOfJunctionGroups.count(namegrp))
11406                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11407               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11408               if (sgrp)
11409                 sgrp->Add(vol->GetID());
11410             }
11411
11412           // --- modify the face
11413
11414           aFace->ChangeNodes(&ln[0], ln.size());
11415         }
11416     }
11417   return true;
11418 }
11419
11420 /*!
11421  *  \brief identify all the elements around a geom shape, get the faces delimiting the hole
11422  *  Build groups of volume to remove, groups of faces to replace on the skin of the object,
11423  *  groups of faces to remove inside the object, (idem edges).
11424  *  Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape)
11425  */
11426 void SMESH_MeshEditor::CreateHoleSkin(double radius,
11427                                       const TopoDS_Shape& theShape,
11428                                       SMESH_NodeSearcher* theNodeSearcher,
11429                                       const char* groupName,
11430                                       std::vector<double>&   nodesCoords,
11431                                       std::vector<std::vector<int> >& listOfListOfNodes)
11432 {
11433   MESSAGE("--------------------------------");
11434   MESSAGE("SMESH_MeshEditor::CreateHoleSkin");
11435   MESSAGE("--------------------------------");
11436
11437   // --- zone of volumes to remove is given :
11438   //     1 either by a geom shape (one or more vertices) and a radius,
11439   //     2 either by a group of nodes (representative of the shape)to use with the radius,
11440   //     3 either by a group of nodes where all the elements build on one of this nodes are to remove,
11441   //     In the case 2, the group of nodes is an external group of nodes from another mesh,
11442   //     In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter),
11443   //     defined by it's name.
11444
11445   SMESHDS_GroupBase* groupDS = 0;
11446   SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups();
11447   while ( groupIt->more() )
11448     {
11449       groupDS = 0;
11450       SMESH_Group * group = groupIt->next();
11451       if ( !group ) continue;
11452       groupDS = group->GetGroupDS();
11453       if ( !groupDS || groupDS->IsEmpty() ) continue;
11454       std::string grpName = group->GetName();
11455       //MESSAGE("grpName=" << grpName);
11456       if (grpName == groupName)
11457         break;
11458       else
11459         groupDS = 0;
11460     }
11461
11462   bool isNodeGroup = false;
11463   bool isNodeCoords = false;
11464   if (groupDS)
11465     {
11466       if (groupDS->GetType() != SMDSAbs_Node)
11467         return;
11468       isNodeGroup = true;     // a group of nodes exists and it is in this mesh
11469     }
11470
11471   if (nodesCoords.size() > 0)
11472     isNodeCoords = true; // a list o nodes given by their coordinates
11473   //MESSAGE("---" << isNodeGroup << " " << isNodeCoords);
11474
11475   // --- define groups to build
11476
11477   int idg; // --- group of SMDS volumes
11478   string grpvName = groupName;
11479   grpvName += "_vol";
11480   SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
11481   if (!grp)
11482     {
11483       MESSAGE("group not created " << grpvName);
11484       return;
11485     }
11486   SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
11487
11488   int idgs; // --- group of SMDS faces on the skin
11489   string grpsName = groupName;
11490   grpsName += "_skin";
11491   SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
11492   if (!grps)
11493     {
11494       MESSAGE("group not created " << grpsName);
11495       return;
11496     }
11497   SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
11498
11499   int idgi; // --- group of SMDS faces internal (several shapes)
11500   string grpiName = groupName;
11501   grpiName += "_internalFaces";
11502   SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
11503   if (!grpi)
11504     {
11505       MESSAGE("group not created " << grpiName);
11506       return;
11507     }
11508   SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
11509
11510   int idgei; // --- group of SMDS faces internal (several shapes)
11511   string grpeiName = groupName;
11512   grpeiName += "_internalEdges";
11513   SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
11514   if (!grpei)
11515     {
11516       MESSAGE("group not created " << grpeiName);
11517       return;
11518     }
11519   SMESHDS_Group *sgrpei = dynamic_cast<SMESHDS_Group*>(grpei->GetGroupDS());
11520
11521   // --- build downward connectivity
11522
11523   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11524   meshDS->BuildDownWardConnectivity(true);
11525   SMDS_UnstructuredGrid* grid = meshDS->getGrid();
11526
11527   // --- set of volumes detected inside
11528
11529   std::set<int> setOfInsideVol;
11530   std::set<int> setOfVolToCheck;
11531
11532   std::vector<gp_Pnt> gpnts;
11533   gpnts.clear();
11534
11535   if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
11536     {
11537       MESSAGE("group of nodes provided");
11538       SMDS_ElemIteratorPtr elemIt = groupDS->GetElements();
11539       while ( elemIt->more() )
11540         {
11541           const SMDS_MeshElement* elem = elemIt->next();
11542           if (!elem)
11543             continue;
11544           const SMDS_MeshNode* node = dynamic_cast<const SMDS_MeshNode*>(elem);
11545           if (!node)
11546             continue;
11547           SMDS_MeshElement* vol = 0;
11548           SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume);
11549           while (volItr->more())
11550             {
11551               vol = (SMDS_MeshElement*)volItr->next();
11552               setOfInsideVol.insert(vol->getVtkId());
11553               sgrp->Add(vol->GetID());
11554             }
11555         }
11556     }
11557   else if (isNodeCoords)
11558     {
11559       MESSAGE("list of nodes coordinates provided");
11560       int i = 0;
11561       int k = 0;
11562       while (i < nodesCoords.size()-2)
11563         {
11564           double x = nodesCoords[i++];
11565           double y = nodesCoords[i++];
11566           double z = nodesCoords[i++];
11567           gp_Pnt p = gp_Pnt(x, y ,z);
11568           gpnts.push_back(p);
11569           MESSAGE("TopoDS_Vertex " << k << " " << p.X() << " " << p.Y() << " " << p.Z());
11570           k++;
11571         }
11572     }
11573   else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius
11574     {
11575       MESSAGE("no group of nodes provided, using vertices from geom shape, and radius");
11576       TopTools_IndexedMapOfShape vertexMap;
11577       TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap );
11578       gp_Pnt p = gp_Pnt(0,0,0);
11579       if (vertexMap.Extent() < 1)
11580         return;
11581
11582       for ( int i = 1; i <= vertexMap.Extent(); ++i )
11583         {
11584           const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i ));
11585           p = BRep_Tool::Pnt(vertex);
11586           gpnts.push_back(p);
11587           MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z());
11588         }
11589     }
11590
11591   if (gpnts.size() > 0)
11592     {
11593       int nodeId = 0;
11594       const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
11595       if (startNode)
11596         nodeId = startNode->GetID();
11597       MESSAGE("nodeId " << nodeId);
11598
11599       double radius2 = radius*radius;
11600       MESSAGE("radius2 " << radius2);
11601
11602       // --- volumes on start node
11603
11604       setOfVolToCheck.clear();
11605       SMDS_MeshElement* startVol = 0;
11606       SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
11607       while (volItr->more())
11608         {
11609           startVol = (SMDS_MeshElement*)volItr->next();
11610           setOfVolToCheck.insert(startVol->getVtkId());
11611         }
11612       if (setOfVolToCheck.empty())
11613         {
11614           MESSAGE("No volumes found");
11615           return;
11616         }
11617
11618       // --- starting with central volumes then their neighbors, check if they are inside
11619       //     or outside the domain, until no more new neighbor volume is inside.
11620       //     Fill the group of inside volumes
11621
11622       std::map<int, double> mapOfNodeDistance2;
11623       mapOfNodeDistance2.clear();
11624       std::set<int> setOfOutsideVol;
11625       while (!setOfVolToCheck.empty())
11626         {
11627           std::set<int>::iterator it = setOfVolToCheck.begin();
11628           int vtkId = *it;
11629           MESSAGE("volume to check,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11630           bool volInside = false;
11631           vtkIdType npts = 0;
11632           vtkIdType* pts = 0;
11633           grid->GetCellPoints(vtkId, npts, pts);
11634           for (int i=0; i<npts; i++)
11635             {
11636               double distance2 = 0;
11637               if (mapOfNodeDistance2.count(pts[i]))
11638                 {
11639                   distance2 = mapOfNodeDistance2[pts[i]];
11640                   MESSAGE("point " << pts[i] << " distance2 " << distance2);
11641                 }
11642               else
11643                 {
11644                   double *coords = grid->GetPoint(pts[i]);
11645                   gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
11646                   distance2 = 1.E40;
11647                   for (int j=0; j<gpnts.size(); j++)
11648                     {
11649                       double d2 = aPoint.SquareDistance(gpnts[j]);
11650                       if (d2 < distance2)
11651                         {
11652                           distance2 = d2;
11653                           if (distance2 < radius2)
11654                             break;
11655                         }
11656                     }
11657                   mapOfNodeDistance2[pts[i]] = distance2;
11658                   MESSAGE("  point "  << pts[i]  << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " <<  coords[2]);
11659                 }
11660               if (distance2 < radius2)
11661                 {
11662                   volInside = true; // one or more nodes inside the domain
11663                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
11664                   break;
11665                 }
11666             }
11667           if (volInside)
11668             {
11669               setOfInsideVol.insert(vtkId);
11670               MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11671               int neighborsVtkIds[NBMAXNEIGHBORS];
11672               int downIds[NBMAXNEIGHBORS];
11673               unsigned char downTypes[NBMAXNEIGHBORS];
11674               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11675               for (int n = 0; n < nbNeighbors; n++)
11676                 if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n]))
11677                   setOfVolToCheck.insert(neighborsVtkIds[n]);
11678             }
11679           else
11680             {
11681               setOfOutsideVol.insert(vtkId);
11682               MESSAGE("  volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11683             }
11684           setOfVolToCheck.erase(vtkId);
11685         }
11686     }
11687
11688   // --- for outside hexahedrons, check if they have more than one neighbor volume inside
11689   //     If yes, add the volume to the inside set
11690
11691   bool addedInside = true;
11692   std::set<int> setOfVolToReCheck;
11693   while (addedInside)
11694     {
11695       MESSAGE(" --------------------------- re check");
11696       addedInside = false;
11697       std::set<int>::iterator itv = setOfInsideVol.begin();
11698       for (; itv != setOfInsideVol.end(); ++itv)
11699         {
11700           int vtkId = *itv;
11701           int neighborsVtkIds[NBMAXNEIGHBORS];
11702           int downIds[NBMAXNEIGHBORS];
11703           unsigned char downTypes[NBMAXNEIGHBORS];
11704           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11705           for (int n = 0; n < nbNeighbors; n++)
11706             if (!setOfInsideVol.count(neighborsVtkIds[n]))
11707               setOfVolToReCheck.insert(neighborsVtkIds[n]);
11708         }
11709       setOfVolToCheck = setOfVolToReCheck;
11710       setOfVolToReCheck.clear();
11711       while  (!setOfVolToCheck.empty())
11712         {
11713           std::set<int>::iterator it = setOfVolToCheck.begin();
11714           int vtkId = *it;
11715           if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON)
11716             {
11717               MESSAGE("volume to recheck,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11718               int countInside = 0;
11719               int neighborsVtkIds[NBMAXNEIGHBORS];
11720               int downIds[NBMAXNEIGHBORS];
11721               unsigned char downTypes[NBMAXNEIGHBORS];
11722               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11723               for (int n = 0; n < nbNeighbors; n++)
11724                 if (setOfInsideVol.count(neighborsVtkIds[n]))
11725                   countInside++;
11726               MESSAGE("countInside " << countInside);
11727               if (countInside > 1)
11728                 {
11729                   MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11730                   setOfInsideVol.insert(vtkId);
11731                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
11732                   addedInside = true;
11733                 }
11734               else
11735                 setOfVolToReCheck.insert(vtkId);
11736             }
11737           setOfVolToCheck.erase(vtkId);
11738         }
11739     }
11740
11741   // --- map of Downward faces at the boundary, inside the global volume
11742   //     map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin)
11743   //     fill group of SMDS faces inside the volume (when several volume shapes)
11744   //     fill group of SMDS faces on the skin of the global volume (if skin)
11745
11746   std::map<DownIdType, int, DownIdCompare> boundaryFaces; // boundary faces inside the volume --> corresponding cell
11747   std::map<DownIdType, int, DownIdCompare> skinFaces;     // faces on the skin of the global volume --> corresponding cell
11748   std::set<int>::iterator it = setOfInsideVol.begin();
11749   for (; it != setOfInsideVol.end(); ++it)
11750     {
11751       int vtkId = *it;
11752       //MESSAGE("  vtkId " << vtkId  << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11753       int neighborsVtkIds[NBMAXNEIGHBORS];
11754       int downIds[NBMAXNEIGHBORS];
11755       unsigned char downTypes[NBMAXNEIGHBORS];
11756       int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true);
11757       for (int n = 0; n < nbNeighbors; n++)
11758         {
11759           int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n]));
11760           if (neighborDim == 3)
11761             {
11762               if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary
11763                 {
11764                   DownIdType face(downIds[n], downTypes[n]);
11765                   boundaryFaces[face] = vtkId;
11766                 }
11767               // if the face between to volumes is in the mesh, get it (internal face between shapes)
11768               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
11769               if (vtkFaceId >= 0)
11770                 {
11771                   sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId));
11772                   // find also the smds edges on this face
11773                   int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]);
11774                   const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]);
11775                   const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]);
11776                   for (int i = 0; i < nbEdges; i++)
11777                     {
11778                       int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]);
11779                       if (vtkEdgeId >= 0)
11780                         sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId));
11781                     }
11782                 }
11783             }
11784           else if (neighborDim == 2) // skin of the volume
11785             {
11786               DownIdType face(downIds[n], downTypes[n]);
11787               skinFaces[face] = vtkId;
11788               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
11789               if (vtkFaceId >= 0)
11790                 sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId));
11791             }
11792         }
11793     }
11794
11795   // --- identify the edges constituting the wire of each subshape on the skin
11796   //     define polylines with the nodes of edges, equivalent to wires
11797   //     project polylines on subshapes, and partition, to get geom faces
11798
11799   std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
11800   std::set<int> emptySet;
11801   emptySet.clear();
11802   std::set<int> shapeIds;
11803
11804   SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
11805   while (itelem->more())
11806     {
11807       const SMDS_MeshElement *elem = itelem->next();
11808       int shapeId = elem->getshapeId();
11809       int vtkId = elem->getVtkId();
11810       if (!shapeIdToVtkIdSet.count(shapeId))
11811         {
11812           shapeIdToVtkIdSet[shapeId] = emptySet;
11813           shapeIds.insert(shapeId);
11814         }
11815       shapeIdToVtkIdSet[shapeId].insert(vtkId);
11816     }
11817
11818   std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
11819   std::set<DownIdType, DownIdCompare> emptyEdges;
11820   emptyEdges.clear();
11821
11822   std::map<int, std::set<int> >::iterator itShape =  shapeIdToVtkIdSet.begin();
11823   for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
11824     {
11825       int shapeId = itShape->first;
11826       MESSAGE(" --- Shape ID --- "<< shapeId);
11827       shapeIdToEdges[shapeId] = emptyEdges;
11828
11829       std::vector<int> nodesEdges;
11830
11831       std::set<int>::iterator its = itShape->second.begin();
11832       for (; its != itShape->second.end(); ++its)
11833         {
11834           int vtkId = *its;
11835           MESSAGE("     " << vtkId);
11836           int neighborsVtkIds[NBMAXNEIGHBORS];
11837           int downIds[NBMAXNEIGHBORS];
11838           unsigned char downTypes[NBMAXNEIGHBORS];
11839           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11840           for (int n = 0; n < nbNeighbors; n++)
11841             {
11842               if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
11843                 continue;
11844               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
11845               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11846               if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
11847                 {
11848                   DownIdType edge(downIds[n], downTypes[n]);
11849                   if (!shapeIdToEdges[shapeId].count(edge))
11850                     {
11851                       shapeIdToEdges[shapeId].insert(edge);
11852                       int vtkNodeId[3];
11853                       int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId);
11854                       nodesEdges.push_back(vtkNodeId[0]);
11855                       nodesEdges.push_back(vtkNodeId[nbNodes-1]);
11856                       MESSAGE("       --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1);
11857                     }
11858                 }
11859             }
11860         }
11861
11862       std::list<int> order;
11863       order.clear();
11864       if (nodesEdges.size() > 0)
11865         {
11866           order.push_back(nodesEdges[0]); MESSAGE("       --- back " << order.back()+1); // SMDS id = VTK id + 1;
11867           nodesEdges[0] = -1;
11868           order.push_back(nodesEdges[1]); MESSAGE("       --- back " << order.back()+1);
11869           nodesEdges[1] = -1; // do not reuse this edge
11870           bool found = true;
11871           while (found)
11872             {
11873               int nodeTofind = order.back(); // try first to push back
11874               int i = 0;
11875               for (i = 0; i<nodesEdges.size(); i++)
11876                 if (nodesEdges[i] == nodeTofind)
11877                   break;
11878               if (i == nodesEdges.size())
11879                 found = false; // no follower found on back
11880               else
11881                 {
11882                   if (i%2) // odd ==> use the previous one
11883                     if (nodesEdges[i-1] < 0)
11884                       found = false;
11885                     else
11886                       {
11887                         order.push_back(nodesEdges[i-1]); MESSAGE("       --- back " << order.back()+1);
11888                         nodesEdges[i-1] = -1;
11889                       }
11890                   else // even ==> use the next one
11891                     if (nodesEdges[i+1] < 0)
11892                       found = false;
11893                     else
11894                       {
11895                         order.push_back(nodesEdges[i+1]); MESSAGE("       --- back " << order.back()+1);
11896                         nodesEdges[i+1] = -1;
11897                       }
11898                 }
11899               if (found)
11900                 continue;
11901               // try to push front
11902               found = true;
11903               nodeTofind = order.front(); // try to push front
11904               for (i = 0; i<nodesEdges.size(); i++)
11905                 if (nodesEdges[i] == nodeTofind)
11906                   break;
11907               if (i == nodesEdges.size())
11908                 {
11909                   found = false; // no predecessor found on front
11910                   continue;
11911                 }
11912               if (i%2) // odd ==> use the previous one
11913                 if (nodesEdges[i-1] < 0)
11914                   found = false;
11915                 else
11916                   {
11917                     order.push_front(nodesEdges[i-1]); MESSAGE("       --- front " << order.front()+1);
11918                     nodesEdges[i-1] = -1;
11919                   }
11920               else // even ==> use the next one
11921                 if (nodesEdges[i+1] < 0)
11922                   found = false;
11923                 else
11924                   {
11925                     order.push_front(nodesEdges[i+1]); MESSAGE("       --- front " << order.front()+1);
11926                     nodesEdges[i+1] = -1;
11927                   }
11928             }
11929         }
11930
11931
11932       std::vector<int> nodes;
11933       nodes.push_back(shapeId);
11934       std::list<int>::iterator itl = order.begin();
11935       for (; itl != order.end(); itl++)
11936         {
11937           nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
11938           MESSAGE("              ordered node " << nodes[nodes.size()-1]);
11939         }
11940       listOfListOfNodes.push_back(nodes);
11941     }
11942
11943   //     partition geom faces with blocFissure
11944   //     mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose)
11945   //     mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose)
11946
11947   return;
11948 }
11949
11950
11951 //================================================================================
11952 /*!
11953  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11954  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11955  * \return TRUE if operation has been completed successfully, FALSE otherwise
11956  */
11957 //================================================================================
11958
11959 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11960 {
11961   // iterates on volume elements and detect all free faces on them
11962   SMESHDS_Mesh* aMesh = GetMeshDS();
11963   if (!aMesh)
11964     return false;
11965   //bool res = false;
11966   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11967   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11968   while(vIt->more())
11969   {
11970     const SMDS_MeshVolume* volume = vIt->next();
11971     SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
11972     vTool.SetExternalNormal();
11973     //const bool isPoly = volume->IsPoly();
11974     const int iQuad = volume->IsQuadratic();
11975     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11976     {
11977       if (!vTool.IsFreeFace(iface))
11978         continue;
11979       nbFree++;
11980       vector<const SMDS_MeshNode *> nodes;
11981       int nbFaceNodes = vTool.NbFaceNodes(iface);
11982       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11983       int inode = 0;
11984       for ( ; inode < nbFaceNodes; inode += iQuad+1)
11985         nodes.push_back(faceNodes[inode]);
11986       if (iQuad) { // add medium nodes
11987         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11988           nodes.push_back(faceNodes[inode]);
11989         if ( nbFaceNodes == 9 ) // bi-quadratic quad
11990           nodes.push_back(faceNodes[8]);
11991       }
11992       // add new face based on volume nodes
11993       if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
11994         nbExisted++;
11995         continue; // face already exsist
11996       }
11997       AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
11998       nbCreated++;
11999     }
12000   }
12001   return ( nbFree==(nbExisted+nbCreated) );
12002 }
12003
12004 namespace
12005 {
12006   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
12007   {
12008     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
12009       return n;
12010     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
12011   }
12012 }
12013 //================================================================================
12014 /*!
12015  * \brief Creates missing boundary elements
12016  *  \param elements - elements whose boundary is to be checked
12017  *  \param dimension - defines type of boundary elements to create
12018  *  \param group - a group to store created boundary elements in
12019  *  \param targetMesh - a mesh to store created boundary elements in
12020  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
12021  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
12022  *                                boundary elements will be copied into the targetMesh
12023  *  \param toAddExistingBondary - if true, not only new but also pre-existing
12024  *                                boundary elements will be added into the new group
12025  *  \param aroundElements - if true, elements will be created on boundary of given
12026  *                          elements else, on boundary of the whole mesh.
12027  * \return nb of added boundary elements
12028  */
12029 //================================================================================
12030
12031 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
12032                                        Bnd_Dimension           dimension,
12033                                        SMESH_Group*            group/*=0*/,
12034                                        SMESH_Mesh*             targetMesh/*=0*/,
12035                                        bool                    toCopyElements/*=false*/,
12036                                        bool                    toCopyExistingBoundary/*=false*/,
12037                                        bool                    toAddExistingBondary/*= false*/,
12038                                        bool                    aroundElements/*= false*/)
12039 {
12040   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
12041   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
12042   // hope that all elements are of the same type, do not check them all
12043   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
12044     throw SALOME_Exception(LOCALIZED("wrong element type"));
12045
12046   if ( !targetMesh )
12047     toCopyElements = toCopyExistingBoundary = false;
12048
12049   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
12050   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
12051   int nbAddedBnd = 0;
12052
12053   // editor adding present bnd elements and optionally holding elements to add to the group
12054   SMESH_MeshEditor* presentEditor;
12055   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
12056   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
12057
12058   SMESH_MesherHelper helper( *myMesh );
12059   const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
12060   SMDS_VolumeTool vTool;
12061   TIDSortedElemSet avoidSet;
12062   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
12063   int inode;
12064
12065   typedef vector<const SMDS_MeshNode*> TConnectivity;
12066
12067   SMDS_ElemIteratorPtr eIt;
12068   if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
12069   else                  eIt = elemSetIterator( elements );
12070
12071   while (eIt->more())
12072   {
12073     const SMDS_MeshElement* elem = eIt->next();
12074     const int              iQuad = elem->IsQuadratic();
12075
12076     // ------------------------------------------------------------------------------------
12077     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
12078     // ------------------------------------------------------------------------------------
12079     vector<const SMDS_MeshElement*> presentBndElems;
12080     vector<TConnectivity>           missingBndElems;
12081     TConnectivity nodes, elemNodes;
12082     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
12083     {
12084       vTool.SetExternalNormal();
12085       const SMDS_MeshElement* otherVol = 0;
12086       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
12087       {
12088         if ( !vTool.IsFreeFace(iface, &otherVol) &&
12089              ( !aroundElements || elements.count( otherVol )))
12090           continue;
12091         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
12092         const int    nbFaceNodes = vTool.NbFaceNodes (iface);
12093         if ( missType == SMDSAbs_Edge ) // boundary edges
12094         {
12095           nodes.resize( 2+iQuad );
12096           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
12097           {
12098             for ( int j = 0; j < nodes.size(); ++j )
12099               nodes[j] =nn[i+j];
12100             if ( const SMDS_MeshElement* edge =
12101                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
12102               presentBndElems.push_back( edge );
12103             else
12104               missingBndElems.push_back( nodes );
12105           }
12106         }
12107         else // boundary face
12108         {
12109           nodes.clear();
12110           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
12111             nodes.push_back( nn[inode] ); // add corner nodes
12112           if (iQuad)
12113             for ( inode = 1; inode < nbFaceNodes; inode += 2)
12114               nodes.push_back( nn[inode] ); // add medium nodes
12115           int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
12116           if ( iCenter > 0 )
12117             nodes.push_back( vTool.GetNodes()[ iCenter ] );
12118
12119           if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
12120                                                                SMDSAbs_Face, /*noMedium=*/false ))
12121             presentBndElems.push_back( f );
12122           else
12123             missingBndElems.push_back( nodes );
12124
12125           if ( targetMesh != myMesh )
12126           {
12127             // add 1D elements on face boundary to be added to a new mesh
12128             const SMDS_MeshElement* edge;
12129             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
12130             {
12131               if ( iQuad )
12132                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
12133               else
12134                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
12135               if ( edge && avoidSet.insert( edge ).second )
12136                 presentBndElems.push_back( edge );
12137             }
12138           }
12139         }
12140       }
12141     }
12142     else if ( elem->GetType() == SMDSAbs_Face ) // elem is a face ------------------------
12143     {
12144       avoidSet.clear(), avoidSet.insert( elem );
12145       elemNodes.assign( SMDS_MeshElement::iterator( elem->interlacedNodesElemIterator() ),
12146                         SMDS_MeshElement::iterator() );
12147       elemNodes.push_back( elemNodes[0] );
12148       nodes.resize( 2 + iQuad );
12149       const int nbLinks = elem->NbCornerNodes();
12150       for ( int i = 0, iN = 0; i < nbLinks; i++, iN += 1+iQuad )
12151       {
12152         nodes[0] = elemNodes[iN];
12153         nodes[1] = elemNodes[iN+1+iQuad];
12154         if ( SMESH_MeshAlgos::FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
12155           continue; // not free link
12156
12157         if ( iQuad ) nodes[2] = elemNodes[iN+1];
12158         if ( const SMDS_MeshElement* edge =
12159              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
12160           presentBndElems.push_back( edge );
12161         else
12162           missingBndElems.push_back( nodes );
12163       }
12164     }
12165
12166     // ---------------------------------
12167     // 2. Add missing boundary elements
12168     // ---------------------------------
12169     if ( targetMesh != myMesh )
12170       // instead of making a map of nodes in this mesh and targetMesh,
12171       // we create nodes with same IDs.
12172       for ( int i = 0; i < missingBndElems.size(); ++i )
12173       {
12174         TConnectivity& srcNodes = missingBndElems[i];
12175         TConnectivity  nodes( srcNodes.size() );
12176         for ( inode = 0; inode < nodes.size(); ++inode )
12177           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
12178         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
12179                                                                    missType,
12180                                                                    /*noMedium=*/false))
12181           continue;
12182         tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
12183         ++nbAddedBnd;
12184       }
12185     else
12186       for ( int i = 0; i < missingBndElems.size(); ++i )
12187       {
12188         TConnectivity& nodes = missingBndElems[i];
12189         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
12190                                                                    missType,
12191                                                                    /*noMedium=*/false))
12192           continue;
12193         SMDS_MeshElement* elem =
12194           tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
12195         ++nbAddedBnd;
12196
12197         // try to set a new element to a shape
12198         if ( myMesh->HasShapeToMesh() )
12199         {
12200           bool ok = true;
12201           set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
12202           const int nbN = nodes.size() / (iQuad+1 );
12203           for ( inode = 0; inode < nbN && ok; ++inode )
12204           {
12205             pair<int, TopAbs_ShapeEnum> i_stype =
12206               helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
12207             if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
12208               mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
12209           }
12210           if ( ok && mediumShapes.size() > 1 )
12211           {
12212             set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
12213             pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
12214             for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
12215             {
12216               if (( ok = ( stype_i->first != stype_i_0.first )))
12217                 ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
12218                                         aMesh->IndexToShape( stype_i_0.second ));
12219             }
12220           }
12221           if ( ok && mediumShapes.begin()->first == missShapeType )
12222             aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
12223         }
12224       }
12225
12226     // ----------------------------------
12227     // 3. Copy present boundary elements
12228     // ----------------------------------
12229     if ( toCopyExistingBoundary )
12230       for ( int i = 0 ; i < presentBndElems.size(); ++i )
12231       {
12232         const SMDS_MeshElement* e = presentBndElems[i];
12233         TConnectivity nodes( e->NbNodes() );
12234         for ( inode = 0; inode < nodes.size(); ++inode )
12235           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
12236         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
12237       }
12238     else // store present elements to add them to a group
12239       for ( int i = 0 ; i < presentBndElems.size(); ++i )
12240       {
12241         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
12242       }
12243
12244   } // loop on given elements
12245
12246   // ---------------------------------------------
12247   // 4. Fill group with boundary elements
12248   // ---------------------------------------------
12249   if ( group )
12250   {
12251     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
12252       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
12253         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
12254   }
12255   tgtEditor.myLastCreatedElems.Clear();
12256   tgtEditor2.myLastCreatedElems.Clear();
12257
12258   // -----------------------
12259   // 5. Copy given elements
12260   // -----------------------
12261   if ( toCopyElements && targetMesh != myMesh )
12262   {
12263     if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
12264     else                  eIt = elemSetIterator( elements );
12265     while (eIt->more())
12266     {
12267       const SMDS_MeshElement* elem = eIt->next();
12268       TConnectivity nodes( elem->NbNodes() );
12269       for ( inode = 0; inode < nodes.size(); ++inode )
12270         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
12271       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
12272
12273       tgtEditor.myLastCreatedElems.Clear();
12274     }
12275   }
12276   return nbAddedBnd;
12277 }