Salome HOME
1) 0022100: EDF 2413 SMESH: Take into account TRIA7
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File      : SMESH_MeshEditor.cxx
24 // Created   : Mon Apr 12 16:10:22 2004
25 // Author    : Edward AGAPOV (eap)
26
27 #include "SMESH_MeshEditor.hxx"
28
29 #include "SMDS_FaceOfNodes.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_EdgePosition.hxx"
32 #include "SMDS_FacePosition.hxx"
33 #include "SMDS_SpacePosition.hxx"
34 #include "SMDS_MeshGroup.hxx"
35 #include "SMDS_LinearEdge.hxx"
36 #include "SMDS_Downward.hxx"
37 #include "SMDS_SetIterator.hxx"
38
39 #include "SMESHDS_Group.hxx"
40 #include "SMESHDS_Mesh.hxx"
41
42 #include "SMESH_Algo.hxx"
43 #include "SMESH_ControlsDef.hxx"
44 #include "SMESH_Group.hxx"
45 #include "SMESH_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
54 #include <BRepAdaptor_Surface.hxx>
55 #include <BRepBuilderAPI_MakeEdge.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
58 #include <ElCLib.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <Geom2d_Curve.hxx>
63 #include <GeomAdaptor_Surface.hxx>
64 #include <Geom_Curve.hxx>
65 #include <Geom_Surface.hxx>
66 #include <Precision.hxx>
67 #include <TColStd_ListOfInteger.hxx>
68 #include <TopAbs_State.hxx>
69 #include <TopExp.hxx>
70 #include <TopExp_Explorer.hxx>
71 #include <TopTools_ListIteratorOfListOfShape.hxx>
72 #include <TopTools_ListOfShape.hxx>
73 #include <TopTools_SequenceOfShape.hxx>
74 #include <TopoDS.hxx>
75 #include <TopoDS_Face.hxx>
76 #include <TopoDS_Solid.hxx>
77 #include <gp.hxx>
78 #include <gp_Ax1.hxx>
79 #include <gp_Dir.hxx>
80 #include <gp_Lin.hxx>
81 #include <gp_Pln.hxx>
82 #include <gp_Trsf.hxx>
83 #include <gp_Vec.hxx>
84 #include <gp_XY.hxx>
85 #include <gp_XYZ.hxx>
86
87 #include <cmath>
88
89 #include <map>
90 #include <set>
91 #include <numeric>
92 #include <limits>
93 #include <algorithm>
94 #include <sstream>
95
96 #include <boost/tuple/tuple.hpp>
97
98 #include <Standard_Failure.hxx>
99 #include <Standard_ErrorHandler.hxx>
100
101 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
102
103 using namespace std;
104 using namespace SMESH::Controls;
105
106 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
107
108 //=======================================================================
109 //function : SMESH_MeshEditor
110 //purpose  :
111 //=======================================================================
112
113 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
114   :myMesh( theMesh ) // theMesh may be NULL
115 {
116 }
117
118 //================================================================================
119 /*!
120  * \brief Clears myLastCreatedNodes and myLastCreatedElems
121  */
122 //================================================================================
123
124 void SMESH_MeshEditor::CrearLastCreated()
125 {
126   myLastCreatedNodes.Clear();
127   myLastCreatedElems.Clear();
128 }
129
130
131 //=======================================================================
132 /*!
133  * \brief Add element
134  */
135 //=======================================================================
136
137 SMDS_MeshElement*
138 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
139                              const SMDSAbs_ElementType            type,
140                              const bool                           isPoly,
141                              const int                            ID,
142                              const double                         ballDiameter)
143 {
144   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
145   SMDS_MeshElement* e = 0;
146   int nbnode = node.size();
147   SMESHDS_Mesh* mesh = GetMeshDS();
148   switch ( type ) {
149   case SMDSAbs_Face:
150     if ( !isPoly ) {
151       if      (nbnode == 3) {
152         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
153         else           e = mesh->AddFace      (node[0], node[1], node[2] );
154       }
155       else if (nbnode == 4) {
156         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
157         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
158       }
159       else if (nbnode == 6) {
160         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
161                                                node[4], node[5], ID);
162         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
163                                                node[4], node[5] );
164       }
165       else if (nbnode == 7) {
166         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
167                                                node[4], node[5], node[6], ID);
168         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
169                                                node[4], node[5], node[6] );
170       }
171       else if (nbnode == 8) {
172         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
173                                                node[4], node[5], node[6], node[7], ID);
174         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
175                                                node[4], node[5], node[6], node[7] );
176       }
177       else if (nbnode == 9) {
178         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
179                                                node[4], node[5], node[6], node[7], node[8], ID);
180         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
181                                                node[4], node[5], node[6], node[7], node[8] );
182       }
183     } else {
184       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
185       else           e = mesh->AddPolygonalFace      (node    );
186     }
187     break;
188
189   case SMDSAbs_Volume:
190     if ( !isPoly ) {
191       if      (nbnode == 4) {
192         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
193         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
194       }
195       else if (nbnode == 5) {
196         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
197                                                  node[4], ID);
198         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
199                                                  node[4] );
200       }
201       else if (nbnode == 6) {
202         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
203                                                  node[4], node[5], ID);
204         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
205                                                  node[4], node[5] );
206       }
207       else if (nbnode == 8) {
208         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
209                                                  node[4], node[5], node[6], node[7], ID);
210         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
211                                                  node[4], node[5], node[6], node[7] );
212       }
213       else if (nbnode == 10) {
214         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
215                                                  node[4], node[5], node[6], node[7],
216                                                  node[8], node[9], ID);
217         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
218                                                  node[4], node[5], node[6], node[7],
219                                                  node[8], node[9] );
220       }
221       else if (nbnode == 12) {
222         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
223                                                  node[4], node[5], node[6], node[7],
224                                                  node[8], node[9], node[10], node[11], ID);
225         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
226                                                  node[4], node[5], node[6], node[7],
227                                                  node[8], node[9], node[10], node[11] );
228       }
229       else if (nbnode == 13) {
230         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
231                                                  node[4], node[5], node[6], node[7],
232                                                  node[8], node[9], node[10],node[11],
233                                                  node[12],ID);
234         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
235                                                  node[4], node[5], node[6], node[7],
236                                                  node[8], node[9], node[10],node[11],
237                                                  node[12] );
238       }
239       else if (nbnode == 15) {
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],node[13],node[14],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],node[13],node[14] );
248       }
249       else if (nbnode == 20) {
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],node[15],
254                                                  node[16],node[17],node[18],node[19],ID);
255         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
256                                                  node[4], node[5], node[6], node[7],
257                                                  node[8], node[9], node[10],node[11],
258                                                  node[12],node[13],node[14],node[15],
259                                                  node[16],node[17],node[18],node[19] );
260       }
261       else if (nbnode == 27) {
262         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
263                                                  node[4], node[5], node[6], node[7],
264                                                  node[8], node[9], node[10],node[11],
265                                                  node[12],node[13],node[14],node[15],
266                                                  node[16],node[17],node[18],node[19],
267                                                  node[20],node[21],node[22],node[23],
268                                                  node[24],node[25],node[26], ID);
269         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
270                                                  node[4], node[5], node[6], node[7],
271                                                  node[8], node[9], node[10],node[11],
272                                                  node[12],node[13],node[14],node[15],
273                                                  node[16],node[17],node[18],node[19],
274                                                  node[20],node[21],node[22],node[23],
275                                                  node[24],node[25],node[26] );
276       }
277     }
278     break;
279
280   case SMDSAbs_Edge:
281     if ( nbnode == 2 ) {
282       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
283       else           e = mesh->AddEdge      (node[0], node[1] );
284     }
285     else if ( nbnode == 3 ) {
286       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
287       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
288     }
289     break;
290
291   case SMDSAbs_0DElement:
292     if ( nbnode == 1 ) {
293       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
294       else           e = mesh->Add0DElement      (node[0] );
295     }
296     break;
297
298   case SMDSAbs_Node:
299     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
300     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
301     break;
302
303   case SMDSAbs_Ball:
304     if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], ballDiameter, ID);
305     else           e = mesh->AddBall      (node[0], ballDiameter);
306     break;
307
308   default:;
309   }
310   if ( e ) myLastCreatedElems.Append( e );
311   return e;
312 }
313
314 //=======================================================================
315 /*!
316  * \brief Add element
317  */
318 //=======================================================================
319
320 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
321                                                const SMDSAbs_ElementType type,
322                                                const bool                isPoly,
323                                                const int                 ID)
324 {
325   vector<const SMDS_MeshNode*> nodes;
326   nodes.reserve( nodeIDs.size() );
327   vector<int>::const_iterator id = nodeIDs.begin();
328   while ( id != nodeIDs.end() ) {
329     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
330       nodes.push_back( node );
331     else
332       return 0;
333   }
334   return AddElement( nodes, type, isPoly, ID );
335 }
336
337 //=======================================================================
338 //function : Remove
339 //purpose  : Remove a node or an element.
340 //           Modify a compute state of sub-meshes which become empty
341 //=======================================================================
342
343 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
344                               const bool         isNodes )
345 {
346   myLastCreatedElems.Clear();
347   myLastCreatedNodes.Clear();
348
349   SMESHDS_Mesh* aMesh = GetMeshDS();
350   set< SMESH_subMesh *> smmap;
351
352   int removed = 0;
353   list<int>::const_iterator it = theIDs.begin();
354   for ( ; it != theIDs.end(); it++ ) {
355     const SMDS_MeshElement * elem;
356     if ( isNodes )
357       elem = aMesh->FindNode( *it );
358     else
359       elem = aMesh->FindElement( *it );
360     if ( !elem )
361       continue;
362
363     // Notify VERTEX sub-meshes about modification
364     if ( isNodes ) {
365       const SMDS_MeshNode* node = cast2Node( elem );
366       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
367         if ( int aShapeID = node->getshapeId() )
368           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
369             smmap.insert( sm );
370     }
371     // Find sub-meshes to notify about modification
372     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
373     //     while ( nodeIt->more() ) {
374     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
375     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
376     //       if ( aPosition.get() ) {
377     //         if ( int aShapeID = aPosition->GetShapeId() ) {
378     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
379     //             smmap.insert( sm );
380     //         }
381     //       }
382     //     }
383
384     // Do remove
385     if ( isNodes )
386       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
387     else
388       aMesh->RemoveElement( elem );
389     removed++;
390   }
391
392   // Notify sub-meshes about modification
393   if ( !smmap.empty() ) {
394     set< SMESH_subMesh *>::iterator smIt;
395     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
396       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
397   }
398
399   //   // Check if the whole mesh becomes empty
400   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
401   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
402
403   return removed;
404 }
405
406 //================================================================================
407 /*!
408  * \brief Create 0D elements on all nodes of the given object except those
409  *        nodes on which a 0D element already exists.
410  *  \param elements - Elements on whose nodes to create 0D elements; if empty, 
411  *                    the all mesh is treated
412  *  \param all0DElems - returns all 0D elements found or created on nodes of \a elements
413  */
414 //================================================================================
415
416 void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements,
417                                                    TIDSortedElemSet&       all0DElems )
418 {
419   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator> TSetIterator;
420   SMDS_ElemIteratorPtr elemIt;
421   if ( elements.empty() )
422     elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node );
423   else
424     elemIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
425
426   while ( elemIt->more() )
427   {
428     const SMDS_MeshElement* e = elemIt->next();
429     SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
430     while ( nodeIt->more() )
431     {
432       const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
433       SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement );
434       if ( it0D->more() )
435         all0DElems.insert( it0D->next() );
436       else {
437         myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n ));
438         all0DElems.insert( myLastCreatedElems.Last() );
439       }
440     }
441   }
442 }
443
444 //=======================================================================
445 //function : FindShape
446 //purpose  : Return an index of the shape theElem is on
447 //           or zero if a shape not found
448 //=======================================================================
449
450 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
451 {
452   myLastCreatedElems.Clear();
453   myLastCreatedNodes.Clear();
454
455   SMESHDS_Mesh * aMesh = GetMeshDS();
456   if ( aMesh->ShapeToMesh().IsNull() )
457     return 0;
458
459   int aShapeID = theElem->getshapeId();
460   if ( aShapeID < 1 )
461     return 0;
462
463   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
464     if ( sm->Contains( theElem ))
465       return aShapeID;
466
467   if ( theElem->GetType() == SMDSAbs_Node ) {
468     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
469   }
470   else {
471     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
472   }
473
474   TopoDS_Shape aShape; // the shape a node of theElem is on
475   if ( theElem->GetType() != SMDSAbs_Node )
476   {
477     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
478     while ( nodeIt->more() ) {
479       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
480       if ((aShapeID = node->getshapeId()) > 0) {
481         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
482           if ( sm->Contains( theElem ))
483             return aShapeID;
484           if ( aShape.IsNull() )
485             aShape = aMesh->IndexToShape( aShapeID );
486         }
487       }
488     }
489   }
490
491   // None of nodes is on a proper shape,
492   // find the shape among ancestors of aShape on which a node is
493   if ( !aShape.IsNull() ) {
494     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
495     for ( ; ancIt.More(); ancIt.Next() ) {
496       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
497       if ( sm && sm->Contains( theElem ))
498         return aMesh->ShapeToIndex( ancIt.Value() );
499     }
500   }
501   else
502   {
503     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
504     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
505     for ( ; id_sm != id2sm.end(); ++id_sm )
506       if ( id_sm->second->Contains( theElem ))
507         return id_sm->first;
508   }
509
510   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
511   return 0;
512 }
513
514 //=======================================================================
515 //function : IsMedium
516 //purpose  :
517 //=======================================================================
518
519 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
520                                 const SMDSAbs_ElementType typeToCheck)
521 {
522   bool isMedium = false;
523   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
524   while (it->more() && !isMedium ) {
525     const SMDS_MeshElement* elem = it->next();
526     isMedium = elem->IsMediumNode(node);
527   }
528   return isMedium;
529 }
530
531 //=======================================================================
532 //function : shiftNodesQuadTria
533 //purpose  : Shift nodes in the array corresponded to quadratic triangle
534 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
535 //=======================================================================
536
537 static void shiftNodesQuadTria(vector< const SMDS_MeshNode* >& aNodes)
538 {
539   const SMDS_MeshNode* nd1 = aNodes[0];
540   aNodes[0] = aNodes[1];
541   aNodes[1] = aNodes[2];
542   aNodes[2] = nd1;
543   const SMDS_MeshNode* nd2 = aNodes[3];
544   aNodes[3] = aNodes[4];
545   aNodes[4] = aNodes[5];
546   aNodes[5] = nd2;
547 }
548
549 //=======================================================================
550 //function : nbEdgeConnectivity
551 //purpose  : return number of the edges connected with the theNode.
552 //           if theEdges has connections with the other type of the
553 //           elements, return -1
554 //=======================================================================
555
556 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
557 {
558   // SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
559   // int nb=0;
560   // while(elemIt->more()) {
561   //   elemIt->next();
562   //   nb++;
563   // }
564   // return nb;
565   return theNode->NbInverseElements();
566 }
567
568 //=======================================================================
569 //function : getNodesFromTwoTria
570 //purpose  : 
571 //=======================================================================
572
573 static bool getNodesFromTwoTria(const SMDS_MeshElement * theTria1,
574                                 const SMDS_MeshElement * theTria2,
575                                 vector< const SMDS_MeshNode*>& N1,
576                                 vector< const SMDS_MeshNode*>& N2)
577 {
578   N1.assign( theTria1->begin_nodes(), theTria1->end_nodes() );
579   if ( N1.size() < 6 ) return false;
580   N2.assign( theTria2->begin_nodes(), theTria2->end_nodes() );
581   if ( N2.size() < 6 ) return false;
582
583   int sames[3] = {-1,-1,-1};
584   int nbsames = 0;
585   int i, j;
586   for(i=0; i<3; i++) {
587     for(j=0; j<3; j++) {
588       if(N1[i]==N2[j]) {
589         sames[i] = j;
590         nbsames++;
591         break;
592       }
593     }
594   }
595   if(nbsames!=2) return false;
596   if(sames[0]>-1) {
597     shiftNodesQuadTria(N1);
598     if(sames[1]>-1) {
599       shiftNodesQuadTria(N1);
600     }
601   }
602   i = sames[0] + sames[1] + sames[2];
603   for(; i<2; i++) {
604     shiftNodesQuadTria(N2);
605   }
606   // now we receive following N1 and N2 (using numeration as in the image below)
607   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
608   // i.e. first nodes from both arrays form a new diagonal
609   return true;
610 }
611
612 //=======================================================================
613 //function : InverseDiag
614 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
615 //           but having other common link.
616 //           Return False if args are improper
617 //=======================================================================
618
619 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
620                                     const SMDS_MeshElement * theTria2 )
621 {
622   MESSAGE("InverseDiag");
623   myLastCreatedElems.Clear();
624   myLastCreatedNodes.Clear();
625
626   if (!theTria1 || !theTria2)
627     return false;
628
629   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
630   if (!F1) return false;
631   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
632   if (!F2) return false;
633   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
634       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
635
636     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
637     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
638     //    |/ |                                         | \|
639     //  B +--+ 2                                     B +--+ 2
640
641     // put nodes in array and find out indices of the same ones
642     const SMDS_MeshNode* aNodes [6];
643     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
644     int i = 0;
645     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
646     while ( it->more() ) {
647       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
648
649       if ( i > 2 ) // theTria2
650         // find same node of theTria1
651         for ( int j = 0; j < 3; j++ )
652           if ( aNodes[ i ] == aNodes[ j ]) {
653             sameInd[ j ] = i;
654             sameInd[ i ] = j;
655             break;
656           }
657       // next
658       i++;
659       if ( i == 3 ) {
660         if ( it->more() )
661           return false; // theTria1 is not a triangle
662         it = theTria2->nodesIterator();
663       }
664       if ( i == 6 && it->more() )
665         return false; // theTria2 is not a triangle
666     }
667
668     // find indices of 1,2 and of A,B in theTria1
669     int iA = 0, iB = 0, i1 = 0, i2 = 0;
670     for ( i = 0; i < 6; i++ ) {
671       if ( sameInd [ i ] == 0 ) {
672         if ( i < 3 ) i1 = i;
673         else         i2 = i;
674       }
675       else if (i < 3) {
676         if ( iA ) iB = i;
677         else      iA = i;
678       }
679     }
680     // nodes 1 and 2 should not be the same
681     if ( aNodes[ i1 ] == aNodes[ i2 ] )
682       return false;
683
684     // theTria1: A->2
685     aNodes[ iA ] = aNodes[ i2 ];
686     // theTria2: B->1
687     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
688
689     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
690     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
691
692     return true;
693
694   } // end if(F1 && F2)
695
696   // check case of quadratic faces
697   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle &&
698       theTria1->GetEntityType() != SMDSEntity_BiQuad_Triangle)
699     return false;
700   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle&&
701       theTria2->GetEntityType() != SMDSEntity_BiQuad_Triangle)
702     return false;
703
704   //       5
705   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
706   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
707   //    |   / |
708   //  7 +  +  + 6
709   //    | /9  |
710   //    |/    |
711   //  4 +--+--+ 3
712   //       8
713
714   vector< const SMDS_MeshNode* > N1;
715   vector< const SMDS_MeshNode* > N2;
716   if(!getNodesFromTwoTria(theTria1,theTria2,N1,N2))
717     return false;
718   // now we receive following N1 and N2 (using numeration as above image)
719   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
720   // i.e. first nodes from both arrays determ new diagonal
721
722   vector< const SMDS_MeshNode*> N1new( N1.size() );
723   vector< const SMDS_MeshNode*> N2new( N2.size() );
724   N1new.back() = N1.back(); // central node of biquadratic
725   N2new.back() = N2.back();
726   N1new[0] = N1[0];  N2new[0] = N1[0];
727   N1new[1] = N2[0];  N2new[1] = N1[1];
728   N1new[2] = N2[1];  N2new[2] = N2[0];
729   N1new[3] = N1[4];  N2new[3] = N1[3];
730   N1new[4] = N2[3];  N2new[4] = N2[5];
731   N1new[5] = N1[5];  N2new[5] = N1[4];
732   // change nodes in faces
733   GetMeshDS()->ChangeElementNodes( theTria1, &N1new[0], N1new.size() );
734   GetMeshDS()->ChangeElementNodes( theTria2, &N2new[0], N2new.size() );
735
736   // move the central node of biquadratic triangle
737   SMESH_MesherHelper helper( *GetMesh() );
738   for ( int is2nd = 0; is2nd < 2; ++is2nd )
739   {
740     const SMDS_MeshElement*         tria = is2nd ? theTria2 : theTria1;
741     vector< const SMDS_MeshNode*>& nodes = is2nd ? N2new : N1new;
742     if ( nodes.size() < 7 )
743       continue;
744     helper.SetSubShape( tria->getshapeId() );
745     const TopoDS_Face& F = TopoDS::Face( helper.GetSubShape() );
746     gp_Pnt xyz;
747     if ( F.IsNull() )
748     {
749       xyz = ( SMESH_TNodeXYZ( nodes[3] ) +
750               SMESH_TNodeXYZ( nodes[4] ) +
751               SMESH_TNodeXYZ( nodes[5] )) / 3.;
752     }
753     else
754     {
755       bool checkUV;
756       gp_XY uv = ( helper.GetNodeUV( F, nodes[3], nodes[2], &checkUV ) +
757                    helper.GetNodeUV( F, nodes[4], nodes[0], &checkUV ) +
758                    helper.GetNodeUV( F, nodes[5], nodes[1], &checkUV )) / 3.;
759       TopLoc_Location loc;
760       Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc);
761       xyz = S->Value( uv.X(), uv.Y() );
762       xyz.Transform( loc );
763       if ( nodes[6]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE &&  // set UV
764            nodes[6]->getshapeId() > 0 )
765         GetMeshDS()->SetNodeOnFace( nodes[6], nodes[6]->getshapeId(), uv.X(), uv.Y() );
766     }
767     GetMeshDS()->MoveNode( nodes[6], xyz.X(), xyz.Y(), xyz.Z() );
768   }
769   return true;
770 }
771
772 //=======================================================================
773 //function : findTriangles
774 //purpose  : find triangles sharing theNode1-theNode2 link
775 //=======================================================================
776
777 static bool findTriangles(const SMDS_MeshNode *    theNode1,
778                           const SMDS_MeshNode *    theNode2,
779                           const SMDS_MeshElement*& theTria1,
780                           const SMDS_MeshElement*& theTria2)
781 {
782   if ( !theNode1 || !theNode2 ) return false;
783
784   theTria1 = theTria2 = 0;
785
786   set< const SMDS_MeshElement* > emap;
787   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
788   while (it->more()) {
789     const SMDS_MeshElement* elem = it->next();
790     if ( elem->NbCornerNodes() == 3 )
791       emap.insert( elem );
792   }
793   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
794   while (it->more()) {
795     const SMDS_MeshElement* elem = it->next();
796     if ( emap.count( elem )) {
797       if ( !theTria1 )
798       {
799         theTria1 = elem;
800       }
801       else  
802       {
803         theTria2 = elem;
804         // theTria1 must be element with minimum ID
805         if ( theTria2->GetID() < theTria1->GetID() )
806           std::swap( theTria2, theTria1 );
807         return true;
808       }
809     }
810   }
811   return false;
812 }
813
814 //=======================================================================
815 //function : InverseDiag
816 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
817 //           with ones built on the same 4 nodes but having other common link.
818 //           Return false if proper faces not found
819 //=======================================================================
820
821 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
822                                     const SMDS_MeshNode * theNode2)
823 {
824   myLastCreatedElems.Clear();
825   myLastCreatedNodes.Clear();
826
827   MESSAGE( "::InverseDiag()" );
828
829   const SMDS_MeshElement *tr1, *tr2;
830   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
831     return false;
832
833   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
834   if (!F1) return false;
835   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
836   if (!F2) return false;
837   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
838       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
839
840     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
841     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
842     //    |/ |                                    | \|
843     //  B +--+ 2                                B +--+ 2
844
845     // put nodes in array
846     // and find indices of 1,2 and of A in tr1 and of B in tr2
847     int i, iA1 = 0, i1 = 0;
848     const SMDS_MeshNode* aNodes1 [3];
849     SMDS_ElemIteratorPtr it;
850     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
851       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
852       if ( aNodes1[ i ] == theNode1 )
853         iA1 = i; // node A in tr1
854       else if ( aNodes1[ i ] != theNode2 )
855         i1 = i;  // node 1
856     }
857     int iB2 = 0, i2 = 0;
858     const SMDS_MeshNode* aNodes2 [3];
859     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
860       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
861       if ( aNodes2[ i ] == theNode2 )
862         iB2 = i; // node B in tr2
863       else if ( aNodes2[ i ] != theNode1 )
864         i2 = i;  // node 2
865     }
866
867     // nodes 1 and 2 should not be the same
868     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
869       return false;
870
871     // tr1: A->2
872     aNodes1[ iA1 ] = aNodes2[ i2 ];
873     // tr2: B->1
874     aNodes2[ iB2 ] = aNodes1[ i1 ];
875
876     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
877     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
878
879     return true;
880   }
881
882   // check case of quadratic faces
883   return InverseDiag(tr1,tr2);
884 }
885
886 //=======================================================================
887 //function : getQuadrangleNodes
888 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
889 //           fusion of triangles tr1 and tr2 having shared link on
890 //           theNode1 and theNode2
891 //=======================================================================
892
893 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
894                         const SMDS_MeshNode *    theNode1,
895                         const SMDS_MeshNode *    theNode2,
896                         const SMDS_MeshElement * tr1,
897                         const SMDS_MeshElement * tr2 )
898 {
899   if( tr1->NbNodes() != tr2->NbNodes() )
900     return false;
901   // find the 4-th node to insert into tr1
902   const SMDS_MeshNode* n4 = 0;
903   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
904   int i=0;
905   while ( !n4 && i<3 ) {
906     const SMDS_MeshNode * n = cast2Node( it->next() );
907     i++;
908     bool isDiag = ( n == theNode1 || n == theNode2 );
909     if ( !isDiag )
910       n4 = n;
911   }
912   // Make an array of nodes to be in a quadrangle
913   int iNode = 0, iFirstDiag = -1;
914   it = tr1->nodesIterator();
915   i=0;
916   while ( i<3 ) {
917     const SMDS_MeshNode * n = cast2Node( it->next() );
918     i++;
919     bool isDiag = ( n == theNode1 || n == theNode2 );
920     if ( isDiag ) {
921       if ( iFirstDiag < 0 )
922         iFirstDiag = iNode;
923       else if ( iNode - iFirstDiag == 1 )
924         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
925     }
926     else if ( n == n4 ) {
927       return false; // tr1 and tr2 should not have all the same nodes
928     }
929     theQuadNodes[ iNode++ ] = n;
930   }
931   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
932     theQuadNodes[ iNode ] = n4;
933
934   return true;
935 }
936
937 //=======================================================================
938 //function : DeleteDiag
939 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
940 //           with a quadrangle built on the same 4 nodes.
941 //           Return false if proper faces not found
942 //=======================================================================
943
944 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
945                                    const SMDS_MeshNode * theNode2)
946 {
947   myLastCreatedElems.Clear();
948   myLastCreatedNodes.Clear();
949
950   MESSAGE( "::DeleteDiag()" );
951
952   const SMDS_MeshElement *tr1, *tr2;
953   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
954     return false;
955
956   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
957   if (!F1) return false;
958   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
959   if (!F2) return false;
960   SMESHDS_Mesh * aMesh = GetMeshDS();
961
962   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
963       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
964
965     const SMDS_MeshNode* aNodes [ 4 ];
966     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
967       return false;
968
969     const SMDS_MeshElement* newElem = 0;
970     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
971     myLastCreatedElems.Append(newElem);
972     AddToSameGroups( newElem, tr1, aMesh );
973     int aShapeId = tr1->getshapeId();
974     if ( aShapeId )
975       {
976         aMesh->SetMeshElementOnShape( newElem, aShapeId );
977       }
978     aMesh->RemoveElement( tr1 );
979     aMesh->RemoveElement( tr2 );
980
981     return true;
982   }
983
984   // check case of quadratic faces
985   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
986     return false;
987   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
988     return false;
989
990   //       5
991   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
992   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
993   //    |   / |
994   //  7 +  +  + 6
995   //    | /9  |
996   //    |/    |
997   //  4 +--+--+ 3
998   //       8
999
1000   vector< const SMDS_MeshNode* > N1;
1001   vector< const SMDS_MeshNode* > N2;
1002   if(!getNodesFromTwoTria(tr1,tr2,N1,N2))
1003     return false;
1004   // now we receive following N1 and N2 (using numeration as above image)
1005   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
1006   // i.e. first nodes from both arrays determ new diagonal
1007
1008   const SMDS_MeshNode* aNodes[8];
1009   aNodes[0] = N1[0];
1010   aNodes[1] = N1[1];
1011   aNodes[2] = N2[0];
1012   aNodes[3] = N2[1];
1013   aNodes[4] = N1[3];
1014   aNodes[5] = N2[5];
1015   aNodes[6] = N2[3];
1016   aNodes[7] = N1[5];
1017
1018   const SMDS_MeshElement* newElem = 0;
1019   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
1020                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
1021   myLastCreatedElems.Append(newElem);
1022   AddToSameGroups( newElem, tr1, aMesh );
1023   int aShapeId = tr1->getshapeId();
1024   if ( aShapeId )
1025     {
1026       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1027     }
1028   aMesh->RemoveElement( tr1 );
1029   aMesh->RemoveElement( tr2 );
1030
1031   // remove middle node (9)
1032   GetMeshDS()->RemoveNode( N1[4] );
1033
1034   return true;
1035 }
1036
1037 //=======================================================================
1038 //function : Reorient
1039 //purpose  : Reverse theElement orientation
1040 //=======================================================================
1041
1042 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
1043 {
1044   MESSAGE("Reorient");
1045   myLastCreatedElems.Clear();
1046   myLastCreatedNodes.Clear();
1047
1048   if (!theElem)
1049     return false;
1050   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
1051   if ( !it || !it->more() )
1052     return false;
1053
1054   const SMDSAbs_ElementType type = theElem->GetType();
1055   if ( type < SMDSAbs_Edge || type > SMDSAbs_Volume )
1056     return false;
1057
1058   const SMDSAbs_EntityType geomType = theElem->GetEntityType();
1059   if ( geomType == SMDSEntity_Polyhedra ) // polyhedron
1060   {
1061     const SMDS_VtkVolume* aPolyedre =
1062       dynamic_cast<const SMDS_VtkVolume*>( theElem );
1063     if (!aPolyedre) {
1064       MESSAGE("Warning: bad volumic element");
1065       return false;
1066     }
1067     const int nbFaces = aPolyedre->NbFaces();
1068     vector<const SMDS_MeshNode *> poly_nodes;
1069     vector<int> quantities (nbFaces);
1070
1071     // reverse each face of the polyedre
1072     for (int iface = 1; iface <= nbFaces; iface++) {
1073       int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1074       quantities[iface - 1] = nbFaceNodes;
1075
1076       for (inode = nbFaceNodes; inode >= 1; inode--) {
1077         const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1078         poly_nodes.push_back(curNode);
1079       }
1080     }
1081     return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1082   }
1083   else // other elements
1084   {
1085     vector<const SMDS_MeshNode*> nodes( theElem->begin_nodes(), theElem->end_nodes() );
1086     const std::vector<int>& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType );
1087     if ( interlace.empty() )
1088     {
1089       std::reverse( nodes.begin(), nodes.end() ); // polygon
1090     }
1091     else if ( interlace.size() > 1 )
1092     {
1093       SMDS_MeshCell::applyInterlace( interlace, nodes );
1094     }
1095     return GetMeshDS()->ChangeElementNodes( theElem, &nodes[0], nodes.size() );
1096   }
1097   return false;
1098 }
1099
1100 //================================================================================
1101 /*!
1102  * \brief Reorient faces.
1103  * \param theFaces - the faces to reorient. If empty the whole mesh is meant
1104  * \param theDirection - desired direction of normal of \a theFace
1105  * \param theFace - one of \a theFaces that sould be oriented according to
1106  *        \a theDirection and whose orientation defines orientation of other faces
1107  * \return number of reoriented faces.
1108  */
1109 //================================================================================
1110
1111 int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
1112                                   const gp_Dir&            theDirection,
1113                                   const SMDS_MeshElement * theFace)
1114 {
1115   int nbReori = 0;
1116   if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori;
1117
1118   if ( theFaces.empty() )
1119   {
1120     SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true);
1121     while ( fIt->more() )
1122       theFaces.insert( theFaces.end(), fIt->next() );
1123   }
1124
1125   // orient theFace according to theDirection
1126   gp_XYZ normal;
1127   SMESH_MeshAlgos::FaceNormal( theFace, normal, /*normalized=*/false );
1128   if ( normal * theDirection.XYZ() < 0 )
1129     nbReori += Reorient( theFace );
1130
1131   // Orient other faces
1132
1133   set< const SMDS_MeshElement* > startFaces, visitedFaces;
1134   TIDSortedElemSet avoidSet;
1135   set< SMESH_TLink > checkedLinks;
1136   pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
1137
1138   if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
1139     theFaces.erase( theFace );
1140   startFaces.insert( theFace );
1141
1142   int nodeInd1, nodeInd2;
1143   const SMDS_MeshElement*           otherFace;
1144   vector< const SMDS_MeshElement* > facesNearLink;
1145   vector< std::pair< int, int > >   nodeIndsOfFace;
1146
1147   set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
1148   while ( !startFaces.empty() )
1149   {
1150     startFace = startFaces.begin();
1151     theFace = *startFace;
1152     startFaces.erase( startFace );
1153     if ( !visitedFaces.insert( theFace ).second )
1154       continue;
1155
1156     avoidSet.clear();
1157     avoidSet.insert(theFace);
1158
1159     NLink link( theFace->GetNode( 0 ), 0 );
1160
1161     const int nbNodes = theFace->NbCornerNodes();
1162     for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
1163     {
1164       link.second = theFace->GetNode(( i+1 ) % nbNodes );
1165       linkIt_isNew = checkedLinks.insert( link );
1166       if ( !linkIt_isNew.second )
1167       {
1168         // link has already been checked and won't be encountered more
1169         // if the group (theFaces) is manifold
1170         //checkedLinks.erase( linkIt_isNew.first );
1171       }
1172       else
1173       {
1174         facesNearLink.clear();
1175         nodeIndsOfFace.clear();
1176         while (( otherFace = SMESH_MeshAlgos::FindFaceInSet( link.first, link.second,
1177                                                              theFaces, avoidSet,
1178                                                              &nodeInd1, &nodeInd2 )))
1179           if ( otherFace != theFace)
1180           {
1181             facesNearLink.push_back( otherFace );
1182             nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 ));
1183             avoidSet.insert( otherFace );
1184           }
1185         if ( facesNearLink.size() > 1 )
1186         {
1187           // NON-MANIFOLD mesh shell !
1188           // select a face most co-directed with theFace,
1189           // other faces won't be visited this time
1190           gp_XYZ NF, NOF;
1191           SMESH_MeshAlgos::FaceNormal( theFace, NF, /*normalized=*/false );
1192           double proj, maxProj = -1;
1193           for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
1194             SMESH_MeshAlgos::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
1195             if (( proj = Abs( NF * NOF )) > maxProj ) {
1196               maxProj = proj;
1197               otherFace = facesNearLink[i];
1198               nodeInd1  = nodeIndsOfFace[i].first;
1199               nodeInd2  = nodeIndsOfFace[i].second;
1200             }
1201           }
1202           // not to visit rejected faces
1203           for ( size_t i = 0; i < facesNearLink.size(); ++i )
1204             if ( facesNearLink[i] != otherFace && theFaces.size() > 1 )
1205               visitedFaces.insert( facesNearLink[i] );
1206         }
1207         else if ( facesNearLink.size() == 1 )
1208         {
1209           otherFace = facesNearLink[0];
1210           nodeInd1  = nodeIndsOfFace.back().first;
1211           nodeInd2  = nodeIndsOfFace.back().second;
1212         }
1213         if ( otherFace && otherFace != theFace)
1214         {
1215           // link must be reverse in otherFace if orientation ot otherFace
1216           // is same as that of theFace
1217           if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
1218           {
1219             nbReori += Reorient( otherFace );
1220           }
1221           startFaces.insert( otherFace );
1222         }
1223       }
1224       std::swap( link.first, link.second ); // reverse the link
1225     }
1226   }
1227   return nbReori;
1228 }
1229
1230 //=======================================================================
1231 //function : getBadRate
1232 //purpose  :
1233 //=======================================================================
1234
1235 static double getBadRate (const SMDS_MeshElement*               theElem,
1236                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1237 {
1238   SMESH::Controls::TSequenceOfXYZ P;
1239   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1240     return 1e100;
1241   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1242   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1243 }
1244
1245 //=======================================================================
1246 //function : QuadToTri
1247 //purpose  : Cut quadrangles into triangles.
1248 //           theCrit is used to select a diagonal to cut
1249 //=======================================================================
1250
1251 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1252                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1253 {
1254   myLastCreatedElems.Clear();
1255   myLastCreatedNodes.Clear();
1256
1257   MESSAGE( "::QuadToTri()" );
1258
1259   if ( !theCrit.get() )
1260     return false;
1261
1262   SMESHDS_Mesh * aMesh = GetMeshDS();
1263
1264   Handle(Geom_Surface) surface;
1265   SMESH_MesherHelper   helper( *GetMesh() );
1266
1267   TIDSortedElemSet::iterator itElem;
1268   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
1269   {
1270     const SMDS_MeshElement* elem = *itElem;
1271     if ( !elem || elem->GetType() != SMDSAbs_Face )
1272       continue;
1273     if ( elem->NbCornerNodes() != 4 )
1274       continue;
1275
1276     // retrieve element nodes
1277     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1278
1279     // compare two sets of possible triangles
1280     double aBadRate1, aBadRate2; // to what extent a set is bad
1281     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1282     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1283     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1284
1285     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1286     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1287     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1288
1289     const int aShapeId = FindShape( elem );
1290     const SMDS_MeshElement* newElem1 = 0;
1291     const SMDS_MeshElement* newElem2 = 0;
1292
1293     if ( !elem->IsQuadratic() ) // split liner quadrangle
1294     {
1295       // for MaxElementLength2D functor we return minimum diagonal for splitting,
1296       // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1297       if ( aBadRate1 <= aBadRate2 ) {
1298         // tr1 + tr2 is better
1299         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1300         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1301       }
1302       else {
1303         // tr3 + tr4 is better
1304         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1305         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1306       }
1307     }
1308     else // split quadratic quadrangle
1309     {
1310       helper.SetIsQuadratic( true );
1311       helper.SetIsBiQuadratic( aNodes.size() == 9 );
1312
1313       helper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem ));
1314       if ( aNodes.size() == 9 )
1315       {
1316         helper.SetIsBiQuadratic( true );
1317         if ( aBadRate1 <= aBadRate2 )
1318           helper.AddTLinkNode( aNodes[0], aNodes[2], aNodes[8] );
1319         else
1320           helper.AddTLinkNode( aNodes[1], aNodes[3], aNodes[8] );
1321       }
1322       // create a new element
1323       if ( aBadRate1 <= aBadRate2 ) {
1324         newElem1 = helper.AddFace( aNodes[2], aNodes[3], aNodes[0] );
1325         newElem2 = helper.AddFace( aNodes[2], aNodes[0], aNodes[1] );
1326       }
1327       else {
1328         newElem1 = helper.AddFace( aNodes[3], aNodes[0], aNodes[1] );
1329         newElem2 = helper.AddFace( aNodes[3], aNodes[1], aNodes[2] );
1330       }
1331     } // quadratic case
1332
1333     // care of a new element
1334
1335     myLastCreatedElems.Append(newElem1);
1336     myLastCreatedElems.Append(newElem2);
1337     AddToSameGroups( newElem1, elem, aMesh );
1338     AddToSameGroups( newElem2, elem, aMesh );
1339
1340     // put a new triangle on the same shape
1341     if ( aShapeId )
1342       aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1343     aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1344
1345     aMesh->RemoveElement( elem );
1346   }
1347   return true;
1348 }
1349
1350 //=======================================================================
1351 //function : BestSplit
1352 //purpose  : Find better diagonal for cutting.
1353 //=======================================================================
1354
1355 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1356                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1357 {
1358   myLastCreatedElems.Clear();
1359   myLastCreatedNodes.Clear();
1360
1361   if (!theCrit.get())
1362     return -1;
1363
1364   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1365     return -1;
1366
1367   if( theQuad->NbNodes()==4 ||
1368       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1369
1370     // retrieve element nodes
1371     const SMDS_MeshNode* aNodes [4];
1372     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1373     int i = 0;
1374     //while (itN->more())
1375     while (i<4) {
1376       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1377     }
1378     // compare two sets of possible triangles
1379     double aBadRate1, aBadRate2; // to what extent a set is bad
1380     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1381     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1382     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1383
1384     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1385     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1386     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1387     // for MaxElementLength2D functor we return minimum diagonal for splitting,
1388     // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1389     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1390       return 1; // diagonal 1-3
1391
1392     return 2; // diagonal 2-4
1393   }
1394   return -1;
1395 }
1396
1397 namespace
1398 {
1399   // Methods of splitting volumes into tetra
1400
1401   const int theHexTo5_1[5*4+1] =
1402     {
1403       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1404     };
1405   const int theHexTo5_2[5*4+1] =
1406     {
1407       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1408     };
1409   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1410
1411   const int theHexTo6_1[6*4+1] =
1412     {
1413       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
1414     };
1415   const int theHexTo6_2[6*4+1] =
1416     {
1417       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
1418     };
1419   const int theHexTo6_3[6*4+1] =
1420     {
1421       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
1422     };
1423   const int theHexTo6_4[6*4+1] =
1424     {
1425       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
1426     };
1427   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1428
1429   const int thePyraTo2_1[2*4+1] =
1430     {
1431       0, 1, 2, 4,    0, 2, 3, 4,   -1
1432     };
1433   const int thePyraTo2_2[2*4+1] =
1434     {
1435       1, 2, 3, 4,    1, 3, 0, 4,   -1
1436     };
1437   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1438
1439   const int thePentaTo3_1[3*4+1] =
1440     {
1441       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1442     };
1443   const int thePentaTo3_2[3*4+1] =
1444     {
1445       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1446     };
1447   const int thePentaTo3_3[3*4+1] =
1448     {
1449       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1450     };
1451   const int thePentaTo3_4[3*4+1] =
1452     {
1453       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1454     };
1455   const int thePentaTo3_5[3*4+1] =
1456     {
1457       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1458     };
1459   const int thePentaTo3_6[3*4+1] =
1460     {
1461       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1462     };
1463   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1464                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1465
1466   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1467   {
1468     int _n1, _n2, _n3;
1469     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1470     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1471     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1472   };
1473   struct TSplitMethod
1474   {
1475     int        _nbTetra;
1476     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1477     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1478     bool       _ownConn;      //!< to delete _connectivity in destructor
1479     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1480
1481     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1482       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1483     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1484     bool hasFacet( const TTriangleFacet& facet ) const
1485     {
1486       const int* tetConn = _connectivity;
1487       for ( ; tetConn[0] >= 0; tetConn += 4 )
1488         if (( facet.contains( tetConn[0] ) +
1489               facet.contains( tetConn[1] ) +
1490               facet.contains( tetConn[2] ) +
1491               facet.contains( tetConn[3] )) == 3 )
1492           return true;
1493       return false;
1494     }
1495   };
1496
1497   //=======================================================================
1498   /*!
1499    * \brief return TSplitMethod for the given element
1500    */
1501   //=======================================================================
1502
1503   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1504   {
1505     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1506
1507     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1508     // an edge and a face barycenter; tertaherdons are based on triangles and
1509     // a volume barycenter
1510     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1511
1512     // Find out how adjacent volumes are split
1513
1514     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1515     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1516     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1517     {
1518       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1519       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1520       if ( nbNodes < 4 ) continue;
1521
1522       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1523       const int* nInd = vol.GetFaceNodesIndices( iF );
1524       if ( nbNodes == 4 )
1525       {
1526         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1527         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1528         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1529         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1530       }
1531       else
1532       {
1533         int iCom = 0; // common node of triangle faces to split into
1534         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1535         {
1536           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1537                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1538                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1539           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1540                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1541                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1542           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1543           {
1544             triaSplits.push_back( t012 );
1545             triaSplits.push_back( t023 );
1546             break;
1547           }
1548         }
1549       }
1550       if ( !triaSplits.empty() )
1551         hasAdjacentSplits = true;
1552     }
1553
1554     // Among variants of split method select one compliant with adjacent volumes
1555
1556     TSplitMethod method;
1557     if ( !vol.Element()->IsPoly() && !is24TetMode )
1558     {
1559       int nbVariants = 2, nbTet = 0;
1560       const int** connVariants = 0;
1561       switch ( vol.Element()->GetEntityType() )
1562       {
1563       case SMDSEntity_Hexa:
1564       case SMDSEntity_Quad_Hexa:
1565       case SMDSEntity_TriQuad_Hexa:
1566         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1567           connVariants = theHexTo5, nbTet = 5;
1568         else
1569           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1570         break;
1571       case SMDSEntity_Pyramid:
1572       case SMDSEntity_Quad_Pyramid:
1573         connVariants = thePyraTo2;  nbTet = 2;
1574         break;
1575       case SMDSEntity_Penta:
1576       case SMDSEntity_Quad_Penta:
1577         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1578         break;
1579       default:
1580         nbVariants = 0;
1581       }
1582       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1583       {
1584         // check method compliancy with adjacent tetras,
1585         // all found splits must be among facets of tetras described by this method
1586         method = TSplitMethod( nbTet, connVariants[variant] );
1587         if ( hasAdjacentSplits && method._nbTetra > 0 )
1588         {
1589           bool facetCreated = true;
1590           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1591           {
1592             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1593             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1594               facetCreated = method.hasFacet( *facet );
1595           }
1596           if ( !facetCreated )
1597             method = TSplitMethod(0); // incompatible method
1598         }
1599       }
1600     }
1601     if ( method._nbTetra < 1 )
1602     {
1603       // No standard method is applicable, use a generic solution:
1604       // each facet of a volume is split into triangles and
1605       // each of triangles and a volume barycenter form a tetrahedron.
1606
1607       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1608
1609       int* connectivity = new int[ maxTetConnSize + 1 ];
1610       method._connectivity = connectivity;
1611       method._ownConn = true;
1612       method._baryNode = !isHex27; // to create central node or not
1613
1614       int connSize = 0;
1615       int baryCenInd = vol.NbNodes() - int( isHex27 );
1616       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1617       {
1618         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1619         const int*   nInd = vol.GetFaceNodesIndices( iF );
1620         // find common node of triangle facets of tetra to create
1621         int iCommon = 0; // index in linear numeration
1622         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1623         if ( !triaSplits.empty() )
1624         {
1625           // by found facets
1626           const TTriangleFacet* facet = &triaSplits.front();
1627           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1628             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1629                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1630               break;
1631         }
1632         else if ( nbNodes > 3 && !is24TetMode )
1633         {
1634           // find the best method of splitting into triangles by aspect ratio
1635           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1636           map< double, int > badness2iCommon;
1637           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1638           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1639           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1640           {
1641             double badness = 0;
1642             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1643             {
1644               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1645                                       nodes[ iQ*((iLast-1)%nbNodes)],
1646                                       nodes[ iQ*((iLast  )%nbNodes)]);
1647               badness += getBadRate( &tria, aspectRatio );
1648             }
1649             badness2iCommon.insert( make_pair( badness, iCommon ));
1650           }
1651           // use iCommon with lowest badness
1652           iCommon = badness2iCommon.begin()->second;
1653         }
1654         if ( iCommon >= nbNodes )
1655           iCommon = 0; // something wrong
1656
1657         // fill connectivity of tetrahedra based on a current face
1658         int nbTet = nbNodes - 2;
1659         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1660         {
1661           int faceBaryCenInd;
1662           if ( isHex27 )
1663           {
1664             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
1665             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
1666           }
1667           else
1668           {
1669             method._faceBaryNode[ iF ] = 0;
1670             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1671           }
1672           nbTet = nbNodes;
1673           for ( int i = 0; i < nbTet; ++i )
1674           {
1675             int i1 = i, i2 = (i+1) % nbNodes;
1676             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1677             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1678             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1679             connectivity[ connSize++ ] = faceBaryCenInd;
1680             connectivity[ connSize++ ] = baryCenInd;
1681           }
1682         }
1683         else
1684         {
1685           for ( int i = 0; i < nbTet; ++i )
1686           {
1687             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1688             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1689             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1690             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1691             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1692             connectivity[ connSize++ ] = baryCenInd;
1693           }
1694         }
1695         method._nbTetra += nbTet;
1696
1697       } // loop on volume faces
1698
1699       connectivity[ connSize++ ] = -1;
1700
1701     } // end of generic solution
1702
1703     return method;
1704   }
1705   //================================================================================
1706   /*!
1707    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1708    */
1709   //================================================================================
1710
1711   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1712   {
1713     // find the tetrahedron including the three nodes of facet
1714     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1715     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1716     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1717     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1718     while ( volIt1->more() )
1719     {
1720       const SMDS_MeshElement* v = volIt1->next();
1721       SMDSAbs_EntityType type = v->GetEntityType();
1722       if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
1723         continue;
1724       if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
1725         continue; // medium node not allowed
1726       const int ind2 = v->GetNodeIndex( n2 );
1727       if ( ind2 < 0 || 3 < ind2 )
1728         continue;
1729       const int ind3 = v->GetNodeIndex( n3 );
1730       if ( ind3 < 0 || 3 < ind3 )
1731         continue;
1732       return true;
1733     }
1734     return false;
1735   }
1736
1737   //=======================================================================
1738   /*!
1739    * \brief A key of a face of volume
1740    */
1741   //=======================================================================
1742
1743   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
1744   {
1745     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1746     {
1747       TIDSortedNodeSet sortedNodes;
1748       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1749       int nbNodes = vol.NbFaceNodes( iF );
1750       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1751       for ( int i = 0; i < nbNodes; i += iQ )
1752         sortedNodes.insert( fNodes[i] );
1753       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1754       first.first   = (*(n++))->GetID();
1755       first.second  = (*(n++))->GetID();
1756       second.first  = (*(n++))->GetID();
1757       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
1758     }
1759   };
1760 } // namespace
1761
1762 //=======================================================================
1763 //function : SplitVolumesIntoTetra
1764 //purpose  : Split volume elements into tetrahedra.
1765 //=======================================================================
1766
1767 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1768                                               const int                theMethodFlags)
1769 {
1770   // std-like iterator on coordinates of nodes of mesh element
1771   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1772   NXyzIterator xyzEnd;
1773
1774   SMDS_VolumeTool    volTool;
1775   SMESH_MesherHelper helper( *GetMesh());
1776
1777   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1778   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1779
1780   SMESH_SequenceOfElemPtr newNodes, newElems;
1781
1782   // map face of volume to it's baricenrtic node
1783   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1784   double bc[3];
1785
1786   TIDSortedElemSet::const_iterator elem = theElems.begin();
1787   for ( ; elem != theElems.end(); ++elem )
1788   {
1789     if ( (*elem)->GetType() != SMDSAbs_Volume )
1790       continue;
1791     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1792     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
1793       continue;
1794
1795     if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
1796
1797     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1798     if ( splitMethod._nbTetra < 1 ) continue;
1799
1800     // find submesh to add new tetras to
1801     if ( !subMesh || !subMesh->Contains( *elem ))
1802     {
1803       int shapeID = FindShape( *elem );
1804       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1805       subMesh = GetMeshDS()->MeshElements( shapeID );
1806     }
1807     int iQ;
1808     if ( (*elem)->IsQuadratic() )
1809     {
1810       iQ = 2;
1811       // add quadratic links to the helper
1812       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1813       {
1814         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1815         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
1816         for ( int iN = 0; iN < nbN; iN += iQ )
1817           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
1818       }
1819       helper.SetIsQuadratic( true );
1820     }
1821     else
1822     {
1823       iQ = 1;
1824       helper.SetIsQuadratic( false );
1825     }
1826     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1827     helper.SetElementsOnShape( true );
1828     if ( splitMethod._baryNode )
1829     {
1830       // make a node at barycenter
1831       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1832       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1833       nodes.push_back( gcNode );
1834       newNodes.Append( gcNode );
1835     }
1836     if ( !splitMethod._faceBaryNode.empty() )
1837     {
1838       // make or find baricentric nodes of faces
1839       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1840       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1841       {
1842         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1843           volFace2BaryNode.insert
1844           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
1845         if ( !f_n->second )
1846         {
1847           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1848           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1849         }
1850         nodes.push_back( iF_n->second = f_n->second );
1851       }
1852     }
1853
1854     // make tetras
1855     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1856     const int* tetConn = splitMethod._connectivity;
1857     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1858       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1859                                                        nodes[ tetConn[1] ],
1860                                                        nodes[ tetConn[2] ],
1861                                                        nodes[ tetConn[3] ]));
1862
1863     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1864
1865     // Split faces on sides of the split volume
1866
1867     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1868     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1869     {
1870       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1871       if ( nbNodes < 4 ) continue;
1872
1873       // find an existing face
1874       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1875                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
1876       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
1877                                                                        /*noMedium=*/false))
1878       {
1879         // make triangles
1880         helper.SetElementsOnShape( false );
1881         vector< const SMDS_MeshElement* > triangles;
1882
1883         // find submesh to add new triangles in
1884         if ( !fSubMesh || !fSubMesh->Contains( face ))
1885         {
1886           int shapeID = FindShape( face );
1887           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1888         }
1889         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1890         if ( iF_n != splitMethod._faceBaryNode.end() )
1891         {
1892           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1893           {
1894             const SMDS_MeshNode* n1 = fNodes[iN];
1895             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
1896             const SMDS_MeshNode *n3 = iF_n->second;
1897             if ( !volTool.IsFaceExternal( iF ))
1898               swap( n2, n3 );
1899             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1900
1901             if ( fSubMesh && n3->getshapeId() < 1 )
1902               fSubMesh->AddNode( n3 );
1903           }
1904         }
1905         else
1906         {
1907           // among possible triangles create ones discribed by split method
1908           const int* nInd = volTool.GetFaceNodesIndices( iF );
1909           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1910           int iCom = 0; // common node of triangle faces to split into
1911           list< TTriangleFacet > facets;
1912           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1913           {
1914             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1915                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1916                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1917             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1918                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1919                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1920             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1921             {
1922               facets.push_back( t012 );
1923               facets.push_back( t023 );
1924               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1925                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1926                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1927                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1928               break;
1929             }
1930           }
1931           list< TTriangleFacet >::iterator facet = facets.begin();
1932           for ( ; facet != facets.end(); ++facet )
1933           {
1934             if ( !volTool.IsFaceExternal( iF ))
1935               swap( facet->_n2, facet->_n3 );
1936             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1937                                                  volNodes[ facet->_n2 ],
1938                                                  volNodes[ facet->_n3 ]));
1939           }
1940         }
1941         for ( int i = 0; i < triangles.size(); ++i )
1942         {
1943           if ( !triangles[i] ) continue;
1944           if ( fSubMesh )
1945             fSubMesh->AddElement( triangles[i]);
1946           newElems.Append( triangles[i] );
1947         }
1948         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1949         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1950       }
1951
1952     } // loop on volume faces to split them into triangles
1953
1954     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1955
1956     if ( geomType == SMDSEntity_TriQuad_Hexa )
1957     {
1958       // remove medium nodes that could become free
1959       for ( int i = 20; i < volTool.NbNodes(); ++i )
1960         if ( volNodes[i]->NbInverseElements() == 0 )
1961           GetMeshDS()->RemoveNode( volNodes[i] );
1962     }
1963   } // loop on volumes to split
1964
1965   myLastCreatedNodes = newNodes;
1966   myLastCreatedElems = newElems;
1967 }
1968
1969 //=======================================================================
1970 //function : AddToSameGroups
1971 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1972 //=======================================================================
1973
1974 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1975                                         const SMDS_MeshElement* elemInGroups,
1976                                         SMESHDS_Mesh *          aMesh)
1977 {
1978   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1979   if (!groups.empty()) {
1980     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1981     for ( ; grIt != groups.end(); grIt++ ) {
1982       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1983       if ( group && group->Contains( elemInGroups ))
1984         group->SMDSGroup().Add( elemToAdd );
1985     }
1986   }
1987 }
1988
1989
1990 //=======================================================================
1991 //function : RemoveElemFromGroups
1992 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1993 //=======================================================================
1994 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1995                                              SMESHDS_Mesh *          aMesh)
1996 {
1997   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1998   if (!groups.empty())
1999   {
2000     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
2001     for (; GrIt != groups.end(); GrIt++)
2002     {
2003       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
2004       if (!grp || grp->IsEmpty()) continue;
2005       grp->SMDSGroup().Remove(removeelem);
2006     }
2007   }
2008 }
2009
2010 //================================================================================
2011 /*!
2012  * \brief Replace elemToRm by elemToAdd in the all groups
2013  */
2014 //================================================================================
2015
2016 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
2017                                             const SMDS_MeshElement* elemToAdd,
2018                                             SMESHDS_Mesh *          aMesh)
2019 {
2020   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2021   if (!groups.empty()) {
2022     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2023     for ( ; grIt != groups.end(); grIt++ ) {
2024       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2025       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
2026         group->SMDSGroup().Add( elemToAdd );
2027     }
2028   }
2029 }
2030
2031 //================================================================================
2032 /*!
2033  * \brief Replace elemToRm by elemToAdd in the all groups
2034  */
2035 //================================================================================
2036
2037 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
2038                                             const vector<const SMDS_MeshElement*>& elemToAdd,
2039                                             SMESHDS_Mesh *                         aMesh)
2040 {
2041   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2042   if (!groups.empty())
2043   {
2044     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2045     for ( ; grIt != groups.end(); grIt++ ) {
2046       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2047       if ( group && group->SMDSGroup().Remove( elemToRm ) )
2048         for ( int i = 0; i < elemToAdd.size(); ++i )
2049           group->SMDSGroup().Add( elemToAdd[ i ] );
2050     }
2051   }
2052 }
2053
2054 //=======================================================================
2055 //function : QuadToTri
2056 //purpose  : Cut quadrangles into triangles.
2057 //           theCrit is used to select a diagonal to cut
2058 //=======================================================================
2059
2060 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
2061                                   const bool         the13Diag)
2062 {
2063   myLastCreatedElems.Clear();
2064   myLastCreatedNodes.Clear();
2065
2066   MESSAGE( "::QuadToTri()" );
2067
2068   SMESHDS_Mesh * aMesh = GetMeshDS();
2069
2070   Handle(Geom_Surface) surface;
2071   SMESH_MesherHelper   helper( *GetMesh() );
2072
2073   TIDSortedElemSet::iterator itElem;
2074   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2075     const SMDS_MeshElement* elem = *itElem;
2076     if ( !elem || elem->GetType() != SMDSAbs_Face )
2077       continue;
2078     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
2079     if(!isquad) continue;
2080
2081     if(elem->NbNodes()==4) {
2082       // retrieve element nodes
2083       const SMDS_MeshNode* aNodes [4];
2084       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2085       int i = 0;
2086       while ( itN->more() )
2087         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2088
2089       int aShapeId = FindShape( elem );
2090       const SMDS_MeshElement* newElem1 = 0;
2091       const SMDS_MeshElement* newElem2 = 0;
2092       if ( the13Diag ) {
2093         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
2094         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
2095       }
2096       else {
2097         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
2098         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
2099       }
2100       myLastCreatedElems.Append(newElem1);
2101       myLastCreatedElems.Append(newElem2);
2102       // put a new triangle on the same shape and add to the same groups
2103       if ( aShapeId )
2104         {
2105           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2106           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2107         }
2108       AddToSameGroups( newElem1, elem, aMesh );
2109       AddToSameGroups( newElem2, elem, aMesh );
2110       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
2111       aMesh->RemoveElement( elem );
2112     }
2113
2114     // Quadratic quadrangle
2115
2116     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
2117
2118       // get surface elem is on
2119       int aShapeId = FindShape( elem );
2120       if ( aShapeId != helper.GetSubShapeID() ) {
2121         surface.Nullify();
2122         TopoDS_Shape shape;
2123         if ( aShapeId > 0 )
2124           shape = aMesh->IndexToShape( aShapeId );
2125         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
2126           TopoDS_Face face = TopoDS::Face( shape );
2127           surface = BRep_Tool::Surface( face );
2128           if ( !surface.IsNull() )
2129             helper.SetSubShape( shape );
2130         }
2131       }
2132
2133       const SMDS_MeshNode* aNodes [8];
2134       const SMDS_MeshNode* inFaceNode = 0;
2135       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2136       int i = 0;
2137       while ( itN->more() ) {
2138         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2139         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
2140              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
2141         {
2142           inFaceNode = aNodes[ i-1 ];
2143         }
2144       }
2145
2146       // find middle point for (0,1,2,3)
2147       // and create a node in this point;
2148       gp_XYZ p( 0,0,0 );
2149       if ( surface.IsNull() ) {
2150         for(i=0; i<4; i++)
2151           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
2152         p /= 4;
2153       }
2154       else {
2155         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
2156         gp_XY uv( 0,0 );
2157         for(i=0; i<4; i++)
2158           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
2159         uv /= 4.;
2160         p = surface->Value( uv.X(), uv.Y() ).XYZ();
2161       }
2162       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
2163       myLastCreatedNodes.Append(newN);
2164
2165       // create a new element
2166       const SMDS_MeshElement* newElem1 = 0;
2167       const SMDS_MeshElement* newElem2 = 0;
2168       if ( the13Diag ) {
2169         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
2170                                   aNodes[6], aNodes[7], newN );
2171         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
2172                                   newN,      aNodes[4], aNodes[5] );
2173       }
2174       else {
2175         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
2176                                   aNodes[7], aNodes[4], newN );
2177         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
2178                                   newN,      aNodes[5], aNodes[6] );
2179       }
2180       myLastCreatedElems.Append(newElem1);
2181       myLastCreatedElems.Append(newElem2);
2182       // put a new triangle on the same shape and add to the same groups
2183       if ( aShapeId )
2184         {
2185           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2186           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2187         }
2188       AddToSameGroups( newElem1, elem, aMesh );
2189       AddToSameGroups( newElem2, elem, aMesh );
2190       aMesh->RemoveElement( elem );
2191     }
2192   }
2193
2194   return true;
2195 }
2196
2197 //=======================================================================
2198 //function : getAngle
2199 //purpose  :
2200 //=======================================================================
2201
2202 double getAngle(const SMDS_MeshElement * tr1,
2203                 const SMDS_MeshElement * tr2,
2204                 const SMDS_MeshNode *    n1,
2205                 const SMDS_MeshNode *    n2)
2206 {
2207   double angle = 2. * M_PI; // bad angle
2208
2209   // get normals
2210   SMESH::Controls::TSequenceOfXYZ P1, P2;
2211   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2212        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2213     return angle;
2214   gp_Vec N1,N2;
2215   if(!tr1->IsQuadratic())
2216     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2217   else
2218     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2219   if ( N1.SquareMagnitude() <= gp::Resolution() )
2220     return angle;
2221   if(!tr2->IsQuadratic())
2222     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2223   else
2224     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2225   if ( N2.SquareMagnitude() <= gp::Resolution() )
2226     return angle;
2227
2228   // find the first diagonal node n1 in the triangles:
2229   // take in account a diagonal link orientation
2230   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2231   for ( int t = 0; t < 2; t++ ) {
2232     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2233     int i = 0, iDiag = -1;
2234     while ( it->more()) {
2235       const SMDS_MeshElement *n = it->next();
2236       if ( n == n1 || n == n2 ) {
2237         if ( iDiag < 0)
2238           iDiag = i;
2239         else {
2240           if ( i - iDiag == 1 )
2241             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2242           else
2243             nFirst[ t ] = n;
2244           break;
2245         }
2246       }
2247       i++;
2248     }
2249   }
2250   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2251     N2.Reverse();
2252
2253   angle = N1.Angle( N2 );
2254   //SCRUTE( angle );
2255   return angle;
2256 }
2257
2258 // =================================================
2259 // class generating a unique ID for a pair of nodes
2260 // and able to return nodes by that ID
2261 // =================================================
2262 class LinkID_Gen {
2263 public:
2264
2265   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2266     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2267   {}
2268
2269   long GetLinkID (const SMDS_MeshNode * n1,
2270                   const SMDS_MeshNode * n2) const
2271   {
2272     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2273   }
2274
2275   bool GetNodes (const long             theLinkID,
2276                  const SMDS_MeshNode* & theNode1,
2277                  const SMDS_MeshNode* & theNode2) const
2278   {
2279     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2280     if ( !theNode1 ) return false;
2281     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2282     if ( !theNode2 ) return false;
2283     return true;
2284   }
2285
2286 private:
2287   LinkID_Gen();
2288   const SMESHDS_Mesh* myMesh;
2289   long                myMaxID;
2290 };
2291
2292
2293 //=======================================================================
2294 //function : TriToQuad
2295 //purpose  : Fuse neighbour triangles into quadrangles.
2296 //           theCrit is used to select a neighbour to fuse with.
2297 //           theMaxAngle is a max angle between element normals at which
2298 //           fusion is still performed.
2299 //=======================================================================
2300
2301 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2302                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2303                                   const double                         theMaxAngle)
2304 {
2305   myLastCreatedElems.Clear();
2306   myLastCreatedNodes.Clear();
2307
2308   MESSAGE( "::TriToQuad()" );
2309
2310   if ( !theCrit.get() )
2311     return false;
2312
2313   SMESHDS_Mesh * aMesh = GetMeshDS();
2314
2315   // Prepare data for algo: build
2316   // 1. map of elements with their linkIDs
2317   // 2. map of linkIDs with their elements
2318
2319   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2320   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2321   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2322   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2323
2324   TIDSortedElemSet::iterator itElem;
2325   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
2326   {
2327     const SMDS_MeshElement* elem = *itElem;
2328     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2329     bool IsTria = ( elem->NbCornerNodes()==3 );
2330     if (!IsTria) continue;
2331
2332     // retrieve element nodes
2333     const SMDS_MeshNode* aNodes [4];
2334     SMDS_NodeIteratorPtr itN = elem->nodeIterator();
2335     int i = 0;
2336     while ( i < 3 )
2337       aNodes[ i++ ] = itN->next();
2338     aNodes[ 3 ] = aNodes[ 0 ];
2339
2340     // fill maps
2341     for ( i = 0; i < 3; i++ ) {
2342       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2343       // check if elements sharing a link can be fused
2344       itLE = mapLi_listEl.find( link );
2345       if ( itLE != mapLi_listEl.end() ) {
2346         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2347           continue;
2348         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2349         //if ( FindShape( elem ) != FindShape( elem2 ))
2350         //  continue; // do not fuse triangles laying on different shapes
2351         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2352           continue; // avoid making badly shaped quads
2353         (*itLE).second.push_back( elem );
2354       }
2355       else {
2356         mapLi_listEl[ link ].push_back( elem );
2357       }
2358       mapEl_setLi [ elem ].insert( link );
2359     }
2360   }
2361   // Clean the maps from the links shared by a sole element, ie
2362   // links to which only one element is bound in mapLi_listEl
2363
2364   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2365     int nbElems = (*itLE).second.size();
2366     if ( nbElems < 2  ) {
2367       const SMDS_MeshElement* elem = (*itLE).second.front();
2368       SMESH_TLink link = (*itLE).first;
2369       mapEl_setLi[ elem ].erase( link );
2370       if ( mapEl_setLi[ elem ].empty() )
2371         mapEl_setLi.erase( elem );
2372     }
2373   }
2374
2375   // Algo: fuse triangles into quadrangles
2376
2377   while ( ! mapEl_setLi.empty() ) {
2378     // Look for the start element:
2379     // the element having the least nb of shared links
2380     const SMDS_MeshElement* startElem = 0;
2381     int minNbLinks = 4;
2382     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2383       int nbLinks = (*itEL).second.size();
2384       if ( nbLinks < minNbLinks ) {
2385         startElem = (*itEL).first;
2386         minNbLinks = nbLinks;
2387         if ( minNbLinks == 1 )
2388           break;
2389       }
2390     }
2391
2392     // search elements to fuse starting from startElem or links of elements
2393     // fused earlyer - startLinks
2394     list< SMESH_TLink > startLinks;
2395     while ( startElem || !startLinks.empty() ) {
2396       while ( !startElem && !startLinks.empty() ) {
2397         // Get an element to start, by a link
2398         SMESH_TLink linkId = startLinks.front();
2399         startLinks.pop_front();
2400         itLE = mapLi_listEl.find( linkId );
2401         if ( itLE != mapLi_listEl.end() ) {
2402           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2403           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2404           for ( ; itE != listElem.end() ; itE++ )
2405             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2406               startElem = (*itE);
2407           mapLi_listEl.erase( itLE );
2408         }
2409       }
2410
2411       if ( startElem ) {
2412         // Get candidates to be fused
2413         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2414         const SMESH_TLink *link12, *link13;
2415         startElem = 0;
2416         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2417         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2418         ASSERT( !setLi.empty() );
2419         set< SMESH_TLink >::iterator itLi;
2420         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2421         {
2422           const SMESH_TLink & link = (*itLi);
2423           itLE = mapLi_listEl.find( link );
2424           if ( itLE == mapLi_listEl.end() )
2425             continue;
2426
2427           const SMDS_MeshElement* elem = (*itLE).second.front();
2428           if ( elem == tr1 )
2429             elem = (*itLE).second.back();
2430           mapLi_listEl.erase( itLE );
2431           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2432             continue;
2433           if ( tr2 ) {
2434             tr3 = elem;
2435             link13 = &link;
2436           }
2437           else {
2438             tr2 = elem;
2439             link12 = &link;
2440           }
2441
2442           // add other links of elem to list of links to re-start from
2443           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2444           set< SMESH_TLink >::iterator it;
2445           for ( it = links.begin(); it != links.end(); it++ ) {
2446             const SMESH_TLink& link2 = (*it);
2447             if ( link2 != link )
2448               startLinks.push_back( link2 );
2449           }
2450         }
2451
2452         // Get nodes of possible quadrangles
2453         const SMDS_MeshNode *n12 [4], *n13 [4];
2454         bool Ok12 = false, Ok13 = false;
2455         const SMDS_MeshNode *linkNode1, *linkNode2;
2456         if(tr2) {
2457           linkNode1 = link12->first;
2458           linkNode2 = link12->second;
2459           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2460             Ok12 = true;
2461         }
2462         if(tr3) {
2463           linkNode1 = link13->first;
2464           linkNode2 = link13->second;
2465           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2466             Ok13 = true;
2467         }
2468
2469         // Choose a pair to fuse
2470         if ( Ok12 && Ok13 ) {
2471           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2472           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2473           double aBadRate12 = getBadRate( &quad12, theCrit );
2474           double aBadRate13 = getBadRate( &quad13, theCrit );
2475           if (  aBadRate13 < aBadRate12 )
2476             Ok12 = false;
2477           else
2478             Ok13 = false;
2479         }
2480
2481         // Make quadrangles
2482         // and remove fused elems and remove links from the maps
2483         mapEl_setLi.erase( tr1 );
2484         if ( Ok12 )
2485         {
2486           mapEl_setLi.erase( tr2 );
2487           mapLi_listEl.erase( *link12 );
2488           if ( tr1->NbNodes() == 3 )
2489           {
2490             const SMDS_MeshElement* newElem = 0;
2491             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2492             myLastCreatedElems.Append(newElem);
2493             AddToSameGroups( newElem, tr1, aMesh );
2494             int aShapeId = tr1->getshapeId();
2495             if ( aShapeId )
2496               aMesh->SetMeshElementOnShape( newElem, aShapeId );
2497             aMesh->RemoveElement( tr1 );
2498             aMesh->RemoveElement( tr2 );
2499           }
2500           else {
2501             vector< const SMDS_MeshNode* > N1;
2502             vector< const SMDS_MeshNode* > N2;
2503             getNodesFromTwoTria(tr1,tr2,N1,N2);
2504             // now we receive following N1 and N2 (using numeration as in image in InverseDiag())
2505             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2506             // i.e. first nodes from both arrays form a new diagonal
2507             const SMDS_MeshNode* aNodes[8];
2508             aNodes[0] = N1[0];
2509             aNodes[1] = N1[1];
2510             aNodes[2] = N2[0];
2511             aNodes[3] = N2[1];
2512             aNodes[4] = N1[3];
2513             aNodes[5] = N2[5];
2514             aNodes[6] = N2[3];
2515             aNodes[7] = N1[5];
2516             const SMDS_MeshElement* newElem = 0;
2517             if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
2518               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2519                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
2520             else
2521               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2522                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2523             myLastCreatedElems.Append(newElem);
2524             AddToSameGroups( newElem, tr1, aMesh );
2525             int aShapeId = tr1->getshapeId();
2526             if ( aShapeId )
2527               aMesh->SetMeshElementOnShape( newElem, aShapeId );
2528             aMesh->RemoveElement( tr1 );
2529             aMesh->RemoveElement( tr2 );
2530             // remove middle node (9)
2531             if ( N1[4]->NbInverseElements() == 0 )
2532               aMesh->RemoveNode( N1[4] );
2533             if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
2534               aMesh->RemoveNode( N1[6] );
2535             if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
2536               aMesh->RemoveNode( N2[6] );
2537           }
2538         }
2539         else if ( Ok13 )
2540         {
2541           mapEl_setLi.erase( tr3 );
2542           mapLi_listEl.erase( *link13 );
2543           if ( tr1->NbNodes() == 3 ) {
2544             const SMDS_MeshElement* newElem = 0;
2545             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2546             myLastCreatedElems.Append(newElem);
2547             AddToSameGroups( newElem, tr1, aMesh );
2548             int aShapeId = tr1->getshapeId();
2549             if ( aShapeId )
2550               aMesh->SetMeshElementOnShape( newElem, aShapeId );
2551             aMesh->RemoveElement( tr1 );
2552             aMesh->RemoveElement( tr3 );
2553           }
2554           else {
2555             vector< const SMDS_MeshNode* > N1;
2556             vector< const SMDS_MeshNode* > N2;
2557             getNodesFromTwoTria(tr1,tr3,N1,N2);
2558             // now we receive following N1 and N2 (using numeration as above image)
2559             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2560             // i.e. first nodes from both arrays form a new diagonal
2561             const SMDS_MeshNode* aNodes[8];
2562             aNodes[0] = N1[0];
2563             aNodes[1] = N1[1];
2564             aNodes[2] = N2[0];
2565             aNodes[3] = N2[1];
2566             aNodes[4] = N1[3];
2567             aNodes[5] = N2[5];
2568             aNodes[6] = N2[3];
2569             aNodes[7] = N1[5];
2570             const SMDS_MeshElement* newElem = 0;
2571             if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
2572               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2573                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
2574             else
2575               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2576                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2577             myLastCreatedElems.Append(newElem);
2578             AddToSameGroups( newElem, tr1, aMesh );
2579             int aShapeId = tr1->getshapeId();
2580             if ( aShapeId )
2581               aMesh->SetMeshElementOnShape( newElem, aShapeId );
2582             aMesh->RemoveElement( tr1 );
2583             aMesh->RemoveElement( tr3 );
2584             // remove middle node (9)
2585             if ( N1[4]->NbInverseElements() == 0 )
2586               aMesh->RemoveNode( N1[4] );
2587             if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
2588               aMesh->RemoveNode( N1[6] );
2589             if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
2590               aMesh->RemoveNode( N2[6] );
2591           }
2592         }
2593
2594         // Next element to fuse: the rejected one
2595         if ( tr3 )
2596           startElem = Ok12 ? tr3 : tr2;
2597
2598       } // if ( startElem )
2599     } // while ( startElem || !startLinks.empty() )
2600   } // while ( ! mapEl_setLi.empty() )
2601
2602   return true;
2603 }
2604
2605
2606 /*#define DUMPSO(txt) \
2607 //  cout << txt << endl;
2608 //=============================================================================
2609 //
2610 //
2611 //
2612 //=============================================================================
2613 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2614 {
2615 if ( i1 == i2 )
2616 return;
2617 int tmp = idNodes[ i1 ];
2618 idNodes[ i1 ] = idNodes[ i2 ];
2619 idNodes[ i2 ] = tmp;
2620 gp_Pnt Ptmp = P[ i1 ];
2621 P[ i1 ] = P[ i2 ];
2622 P[ i2 ] = Ptmp;
2623 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2624 }
2625
2626 //=======================================================================
2627 //function : SortQuadNodes
2628 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2629 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2630 //           1 or 2 else 0.
2631 //=======================================================================
2632
2633 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2634 int               idNodes[] )
2635 {
2636   gp_Pnt P[4];
2637   int i;
2638   for ( i = 0; i < 4; i++ ) {
2639     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2640     if ( !n ) return 0;
2641     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2642   }
2643
2644   gp_Vec V1(P[0], P[1]);
2645   gp_Vec V2(P[0], P[2]);
2646   gp_Vec V3(P[0], P[3]);
2647
2648   gp_Vec Cross1 = V1 ^ V2;
2649   gp_Vec Cross2 = V2 ^ V3;
2650
2651   i = 0;
2652   if (Cross1.Dot(Cross2) < 0)
2653   {
2654     Cross1 = V2 ^ V1;
2655     Cross2 = V1 ^ V3;
2656
2657     if (Cross1.Dot(Cross2) < 0)
2658       i = 2;
2659     else
2660       i = 1;
2661     swap ( i, i + 1, idNodes, P );
2662
2663     //     for ( int ii = 0; ii < 4; ii++ ) {
2664     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2665     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2666     //     }
2667   }
2668   return i;
2669 }
2670
2671 //=======================================================================
2672 //function : SortHexaNodes
2673 //purpose  : Set 8 nodes of a hexahedron in a good order.
2674 //           Return success status
2675 //=======================================================================
2676
2677 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2678                                       int               idNodes[] )
2679 {
2680   gp_Pnt P[8];
2681   int i;
2682   DUMPSO( "INPUT: ========================================");
2683   for ( i = 0; i < 8; i++ ) {
2684     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2685     if ( !n ) return false;
2686     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2687     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2688   }
2689   DUMPSO( "========================================");
2690
2691
2692   set<int> faceNodes;  // ids of bottom face nodes, to be found
2693   set<int> checkedId1; // ids of tried 2-nd nodes
2694   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2695   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2696   int iMin, iLoop1 = 0;
2697
2698   // Loop to try the 2-nd nodes
2699
2700   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2701   {
2702     // Find not checked 2-nd node
2703     for ( i = 1; i < 8; i++ )
2704       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2705         int id1 = idNodes[i];
2706         swap ( 1, i, idNodes, P );
2707         checkedId1.insert ( id1 );
2708         break;
2709       }
2710
2711     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2712     // ie that all but meybe one (id3 which is on the same face) nodes
2713     // lay on the same side from the triangle plane.
2714
2715     bool manyInPlane = false; // more than 4 nodes lay in plane
2716     int iLoop2 = 0;
2717     while ( ++iLoop2 < 6 ) {
2718
2719       // get 1-2-3 plane coeffs
2720       Standard_Real A, B, C, D;
2721       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2722       if ( N.SquareMagnitude() > gp::Resolution() )
2723       {
2724         gp_Pln pln ( P[0], N );
2725         pln.Coefficients( A, B, C, D );
2726
2727         // find the node (iMin) closest to pln
2728         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2729         set<int> idInPln;
2730         for ( i = 3; i < 8; i++ ) {
2731           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2732           if ( fabs( dist[i] ) < minDist ) {
2733             minDist = fabs( dist[i] );
2734             iMin = i;
2735           }
2736           if ( fabs( dist[i] ) <= tol )
2737             idInPln.insert( idNodes[i] );
2738         }
2739
2740         // there should not be more than 4 nodes in bottom plane
2741         if ( idInPln.size() > 1 )
2742         {
2743           DUMPSO( "### idInPln.size() = " << idInPln.size());
2744           // idInPlane does not contain the first 3 nodes
2745           if ( manyInPlane || idInPln.size() == 5)
2746             return false; // all nodes in one plane
2747           manyInPlane = true;
2748
2749           // set the 1-st node to be not in plane
2750           for ( i = 3; i < 8; i++ ) {
2751             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2752               DUMPSO( "### Reset 0-th node");
2753               swap( 0, i, idNodes, P );
2754               break;
2755             }
2756           }
2757
2758           // reset to re-check second nodes
2759           leastDist = DBL_MAX;
2760           faceNodes.clear();
2761           checkedId1.clear();
2762           iLoop1 = 0;
2763           break; // from iLoop2;
2764         }
2765
2766         // check that the other 4 nodes are on the same side
2767         bool sameSide = true;
2768         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2769         for ( i = 3; sameSide && i < 8; i++ ) {
2770           if ( i != iMin )
2771             sameSide = ( isNeg == dist[i] <= 0.);
2772         }
2773
2774         // keep best solution
2775         if ( sameSide && minDist < leastDist ) {
2776           leastDist = minDist;
2777           faceNodes.clear();
2778           faceNodes.insert( idNodes[ 1 ] );
2779           faceNodes.insert( idNodes[ 2 ] );
2780           faceNodes.insert( idNodes[ iMin ] );
2781           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2782                   << " leastDist = " << leastDist);
2783           if ( leastDist <= DBL_MIN )
2784             break;
2785         }
2786       }
2787
2788       // set next 3-d node to check
2789       int iNext = 2 + iLoop2;
2790       if ( iNext < 8 ) {
2791         DUMPSO( "Try 2-nd");
2792         swap ( 2, iNext, idNodes, P );
2793       }
2794     } // while ( iLoop2 < 6 )
2795   } // iLoop1
2796
2797   if ( faceNodes.empty() ) return false;
2798
2799   // Put the faceNodes in proper places
2800   for ( i = 4; i < 8; i++ ) {
2801     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2802       // find a place to put
2803       int iTo = 1;
2804       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2805         iTo++;
2806       DUMPSO( "Set faceNodes");
2807       swap ( iTo, i, idNodes, P );
2808     }
2809   }
2810
2811
2812   // Set nodes of the found bottom face in good order
2813   DUMPSO( " Found bottom face: ");
2814   i = SortQuadNodes( theMesh, idNodes );
2815   if ( i ) {
2816     gp_Pnt Ptmp = P[ i ];
2817     P[ i ] = P[ i+1 ];
2818     P[ i+1 ] = Ptmp;
2819   }
2820   //   else
2821   //     for ( int ii = 0; ii < 4; ii++ ) {
2822   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2823   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2824   //    }
2825
2826   // Gravity center of the top and bottom faces
2827   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2828   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2829
2830   // Get direction from the bottom to the top face
2831   gp_Vec upDir ( aGCb, aGCt );
2832   Standard_Real upDirSize = upDir.Magnitude();
2833   if ( upDirSize <= gp::Resolution() ) return false;
2834   upDir / upDirSize;
2835
2836   // Assure that the bottom face normal points up
2837   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2838   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2839   if ( Nb.Dot( upDir ) < 0 ) {
2840     DUMPSO( "Reverse bottom face");
2841     swap( 1, 3, idNodes, P );
2842   }
2843
2844   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2845   Standard_Real minDist = DBL_MAX;
2846   for ( i = 4; i < 8; i++ ) {
2847     // projection of P[i] to the plane defined by P[0] and upDir
2848     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2849     Standard_Real sqDist = P[0].SquareDistance( Pp );
2850     if ( sqDist < minDist ) {
2851       minDist = sqDist;
2852       iMin = i;
2853     }
2854   }
2855   DUMPSO( "Set 4-th");
2856   swap ( 4, iMin, idNodes, P );
2857
2858   // Set nodes of the top face in good order
2859   DUMPSO( "Sort top face");
2860   i = SortQuadNodes( theMesh, &idNodes[4] );
2861   if ( i ) {
2862     i += 4;
2863     gp_Pnt Ptmp = P[ i ];
2864     P[ i ] = P[ i+1 ];
2865     P[ i+1 ] = Ptmp;
2866   }
2867
2868   // Assure that direction of the top face normal is from the bottom face
2869   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2870   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2871   if ( Nt.Dot( upDir ) < 0 ) {
2872     DUMPSO( "Reverse top face");
2873     swap( 5, 7, idNodes, P );
2874   }
2875
2876   //   DUMPSO( "OUTPUT: ========================================");
2877   //   for ( i = 0; i < 8; i++ ) {
2878   //     float *p = ugrid->GetPoint(idNodes[i]);
2879   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2880   //   }
2881
2882   return true;
2883 }*/
2884
2885 //================================================================================
2886 /*!
2887  * \brief Return nodes linked to the given one
2888  * \param theNode - the node
2889  * \param linkedNodes - the found nodes
2890  * \param type - the type of elements to check
2891  *
2892  * Medium nodes are ignored
2893  */
2894 //================================================================================
2895
2896 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2897                                        TIDSortedElemSet &   linkedNodes,
2898                                        SMDSAbs_ElementType  type )
2899 {
2900   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2901   while ( elemIt->more() )
2902   {
2903     const SMDS_MeshElement* elem = elemIt->next();
2904     if(elem->GetType() == SMDSAbs_0DElement)
2905       continue;
2906
2907     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2908     if ( elem->GetType() == SMDSAbs_Volume )
2909     {
2910       SMDS_VolumeTool vol( elem );
2911       while ( nodeIt->more() ) {
2912         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2913         if ( theNode != n && vol.IsLinked( theNode, n ))
2914           linkedNodes.insert( n );
2915       }
2916     }
2917     else
2918     {
2919       for ( int i = 0; nodeIt->more(); ++i ) {
2920         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2921         if ( n == theNode ) {
2922           int iBefore = i - 1;
2923           int iAfter  = i + 1;
2924           if ( elem->IsQuadratic() ) {
2925             int nb = elem->NbNodes() / 2;
2926             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2927             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2928           }
2929           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2930           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2931         }
2932       }
2933     }
2934   }
2935 }
2936
2937 //=======================================================================
2938 //function : laplacianSmooth
2939 //purpose  : pulls theNode toward the center of surrounding nodes directly
2940 //           connected to that node along an element edge
2941 //=======================================================================
2942
2943 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2944                      const Handle(Geom_Surface)&          theSurface,
2945                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2946 {
2947   // find surrounding nodes
2948
2949   TIDSortedElemSet nodeSet;
2950   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2951
2952   // compute new coodrs
2953
2954   double coord[] = { 0., 0., 0. };
2955   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2956   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2957     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2958     if ( theSurface.IsNull() ) { // smooth in 3D
2959       coord[0] += node->X();
2960       coord[1] += node->Y();
2961       coord[2] += node->Z();
2962     }
2963     else { // smooth in 2D
2964       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2965       gp_XY* uv = theUVMap[ node ];
2966       coord[0] += uv->X();
2967       coord[1] += uv->Y();
2968     }
2969   }
2970   int nbNodes = nodeSet.size();
2971   if ( !nbNodes )
2972     return;
2973   coord[0] /= nbNodes;
2974   coord[1] /= nbNodes;
2975
2976   if ( !theSurface.IsNull() ) {
2977     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2978     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2979     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2980     coord[0] = p3d.X();
2981     coord[1] = p3d.Y();
2982     coord[2] = p3d.Z();
2983   }
2984   else
2985     coord[2] /= nbNodes;
2986
2987   // move node
2988
2989   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2990 }
2991
2992 //=======================================================================
2993 //function : centroidalSmooth
2994 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2995 //           surrounding elements
2996 //=======================================================================
2997
2998 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2999                       const Handle(Geom_Surface)&          theSurface,
3000                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3001 {
3002   gp_XYZ aNewXYZ(0.,0.,0.);
3003   SMESH::Controls::Area anAreaFunc;
3004   double totalArea = 0.;
3005   int nbElems = 0;
3006
3007   // compute new XYZ
3008
3009   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
3010   while ( elemIt->more() )
3011   {
3012     const SMDS_MeshElement* elem = elemIt->next();
3013     nbElems++;
3014
3015     gp_XYZ elemCenter(0.,0.,0.);
3016     SMESH::Controls::TSequenceOfXYZ aNodePoints;
3017     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3018     int nn = elem->NbNodes();
3019     if(elem->IsQuadratic()) nn = nn/2;
3020     int i=0;
3021     //while ( itN->more() ) {
3022     while ( i<nn ) {
3023       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
3024       i++;
3025       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
3026       aNodePoints.push_back( aP );
3027       if ( !theSurface.IsNull() ) { // smooth in 2D
3028         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
3029         gp_XY* uv = theUVMap[ aNode ];
3030         aP.SetCoord( uv->X(), uv->Y(), 0. );
3031       }
3032       elemCenter += aP;
3033     }
3034     double elemArea = anAreaFunc.GetValue( aNodePoints );
3035     totalArea += elemArea;
3036     elemCenter /= nn;
3037     aNewXYZ += elemCenter * elemArea;
3038   }
3039   aNewXYZ /= totalArea;
3040   if ( !theSurface.IsNull() ) {
3041     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
3042     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
3043   }
3044
3045   // move node
3046
3047   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
3048 }
3049
3050 //=======================================================================
3051 //function : getClosestUV
3052 //purpose  : return UV of closest projection
3053 //=======================================================================
3054
3055 static bool getClosestUV (Extrema_GenExtPS& projector,
3056                           const gp_Pnt&     point,
3057                           gp_XY &           result)
3058 {
3059   projector.Perform( point );
3060   if ( projector.IsDone() ) {
3061     double u, v, minVal = DBL_MAX;
3062     for ( int i = projector.NbExt(); i > 0; i-- )
3063 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
3064       if ( projector.SquareDistance( i ) < minVal ) {
3065         minVal = projector.SquareDistance( i );
3066 #else
3067       if ( projector.Value( i ) < minVal ) {
3068         minVal = projector.Value( i );
3069 #endif
3070         projector.Point( i ).Parameter( u, v );
3071       }
3072     result.SetCoord( u, v );
3073     return true;
3074   }
3075   return false;
3076 }
3077
3078 //=======================================================================
3079 //function : Smooth
3080 //purpose  : Smooth theElements during theNbIterations or until a worst
3081 //           element has aspect ratio <= theTgtAspectRatio.
3082 //           Aspect Ratio varies in range [1.0, inf].
3083 //           If theElements is empty, the whole mesh is smoothed.
3084 //           theFixedNodes contains additionally fixed nodes. Nodes built
3085 //           on edges and boundary nodes are always fixed.
3086 //=======================================================================
3087
3088 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
3089                                set<const SMDS_MeshNode*> & theFixedNodes,
3090                                const SmoothMethod          theSmoothMethod,
3091                                const int                   theNbIterations,
3092                                double                      theTgtAspectRatio,
3093                                const bool                  the2D)
3094 {
3095   myLastCreatedElems.Clear();
3096   myLastCreatedNodes.Clear();
3097
3098   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
3099
3100   if ( theTgtAspectRatio < 1.0 )
3101     theTgtAspectRatio = 1.0;
3102
3103   const double disttol = 1.e-16;
3104
3105   SMESH::Controls::AspectRatio aQualityFunc;
3106
3107   SMESHDS_Mesh* aMesh = GetMeshDS();
3108
3109   if ( theElems.empty() ) {
3110     // add all faces to theElems
3111     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
3112     while ( fIt->more() ) {
3113       const SMDS_MeshElement* face = fIt->next();
3114       theElems.insert( theElems.end(), face );
3115     }
3116   }
3117   // get all face ids theElems are on
3118   set< int > faceIdSet;
3119   TIDSortedElemSet::iterator itElem;
3120   if ( the2D )
3121     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3122       int fId = FindShape( *itElem );
3123       // check that corresponding submesh exists and a shape is face
3124       if (fId &&
3125           faceIdSet.find( fId ) == faceIdSet.end() &&
3126           aMesh->MeshElements( fId )) {
3127         TopoDS_Shape F = aMesh->IndexToShape( fId );
3128         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
3129           faceIdSet.insert( fId );
3130       }
3131     }
3132   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
3133
3134   // ===============================================
3135   // smooth elements on each TopoDS_Face separately
3136   // ===============================================
3137
3138   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
3139   for ( ; fId != faceIdSet.rend(); ++fId ) {
3140     // get face surface and submesh
3141     Handle(Geom_Surface) surface;
3142     SMESHDS_SubMesh* faceSubMesh = 0;
3143     TopoDS_Face face;
3144     double fToler2 = 0, f,l;
3145     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
3146     bool isUPeriodic = false, isVPeriodic = false;
3147     if ( *fId ) {
3148       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
3149       surface = BRep_Tool::Surface( face );
3150       faceSubMesh = aMesh->MeshElements( *fId );
3151       fToler2 = BRep_Tool::Tolerance( face );
3152       fToler2 *= fToler2 * 10.;
3153       isUPeriodic = surface->IsUPeriodic();
3154       if ( isUPeriodic )
3155         surface->UPeriod();
3156       isVPeriodic = surface->IsVPeriodic();
3157       if ( isVPeriodic )
3158         surface->VPeriod();
3159       surface->Bounds( u1, u2, v1, v2 );
3160     }
3161     // ---------------------------------------------------------
3162     // for elements on a face, find movable and fixed nodes and
3163     // compute UV for them
3164     // ---------------------------------------------------------
3165     bool checkBoundaryNodes = false;
3166     bool isQuadratic = false;
3167     set<const SMDS_MeshNode*> setMovableNodes;
3168     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3169     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3170     list< const SMDS_MeshElement* > elemsOnFace;
3171
3172     Extrema_GenExtPS projector;
3173     GeomAdaptor_Surface surfAdaptor;
3174     if ( !surface.IsNull() ) {
3175       surfAdaptor.Load( surface );
3176       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3177     }
3178     int nbElemOnFace = 0;
3179     itElem = theElems.begin();
3180     // loop on not yet smoothed elements: look for elems on a face
3181     while ( itElem != theElems.end() ) {
3182       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3183         break; // all elements found
3184
3185       const SMDS_MeshElement* elem = *itElem;
3186       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3187            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3188         ++itElem;
3189         continue;
3190       }
3191       elemsOnFace.push_back( elem );
3192       theElems.erase( itElem++ );
3193       nbElemOnFace++;
3194
3195       if ( !isQuadratic )
3196         isQuadratic = elem->IsQuadratic();
3197
3198       // get movable nodes of elem
3199       const SMDS_MeshNode* node;
3200       SMDS_TypeOfPosition posType;
3201       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3202       int nn = 0, nbn =  elem->NbNodes();
3203       if(elem->IsQuadratic())
3204         nbn = nbn/2;
3205       while ( nn++ < nbn ) {
3206         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3207         const SMDS_PositionPtr& pos = node->GetPosition();
3208         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3209         if (posType != SMDS_TOP_EDGE &&
3210             posType != SMDS_TOP_VERTEX &&
3211             theFixedNodes.find( node ) == theFixedNodes.end())
3212         {
3213           // check if all faces around the node are on faceSubMesh
3214           // because a node on edge may be bound to face
3215           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3216           bool all = true;
3217           if ( faceSubMesh ) {
3218             while ( eIt->more() && all ) {
3219               const SMDS_MeshElement* e = eIt->next();
3220               all = faceSubMesh->Contains( e );
3221             }
3222           }
3223           if ( all )
3224             setMovableNodes.insert( node );
3225           else
3226             checkBoundaryNodes = true;
3227         }
3228         if ( posType == SMDS_TOP_3DSPACE )
3229           checkBoundaryNodes = true;
3230       }
3231
3232       if ( surface.IsNull() )
3233         continue;
3234
3235       // get nodes to check UV
3236       list< const SMDS_MeshNode* > uvCheckNodes;
3237       itN = elem->nodesIterator();
3238       nn = 0; nbn =  elem->NbNodes();
3239       if(elem->IsQuadratic())
3240         nbn = nbn/2;
3241       while ( nn++ < nbn ) {
3242         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3243         if ( uvMap.find( node ) == uvMap.end() )
3244           uvCheckNodes.push_back( node );
3245         // add nodes of elems sharing node
3246         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3247         //         while ( eIt->more() ) {
3248         //           const SMDS_MeshElement* e = eIt->next();
3249         //           if ( e != elem ) {
3250         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3251         //             while ( nIt->more() ) {
3252         //               const SMDS_MeshNode* n =
3253         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3254         //               if ( uvMap.find( n ) == uvMap.end() )
3255         //                 uvCheckNodes.push_back( n );
3256         //             }
3257         //           }
3258         //         }
3259       }
3260       // check UV on face
3261       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3262       for ( ; n != uvCheckNodes.end(); ++n ) {
3263         node = *n;
3264         gp_XY uv( 0, 0 );
3265         const SMDS_PositionPtr& pos = node->GetPosition();
3266         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3267         // get existing UV
3268         switch ( posType ) {
3269         case SMDS_TOP_FACE: {
3270           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3271           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3272           break;
3273         }
3274         case SMDS_TOP_EDGE: {
3275           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3276           Handle(Geom2d_Curve) pcurve;
3277           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3278             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3279           if ( !pcurve.IsNull() ) {
3280             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3281             uv = pcurve->Value( u ).XY();
3282           }
3283           break;
3284         }
3285         case SMDS_TOP_VERTEX: {
3286           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3287           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3288             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3289           break;
3290         }
3291         default:;
3292         }
3293         // check existing UV
3294         bool project = true;
3295         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3296         double dist1 = DBL_MAX, dist2 = 0;
3297         if ( posType != SMDS_TOP_3DSPACE ) {
3298           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3299           project = dist1 > fToler2;
3300         }
3301         if ( project ) { // compute new UV
3302           gp_XY newUV;
3303           if ( !getClosestUV( projector, pNode, newUV )) {
3304             MESSAGE("Node Projection Failed " << node);
3305           }
3306           else {
3307             if ( isUPeriodic )
3308               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3309             if ( isVPeriodic )
3310               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3311             // check new UV
3312             if ( posType != SMDS_TOP_3DSPACE )
3313               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3314             if ( dist2 < dist1 )
3315               uv = newUV;
3316           }
3317         }
3318         // store UV in the map
3319         listUV.push_back( uv );
3320         uvMap.insert( make_pair( node, &listUV.back() ));
3321       }
3322     } // loop on not yet smoothed elements
3323
3324     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3325       checkBoundaryNodes = true;
3326
3327     // fix nodes on mesh boundary
3328
3329     if ( checkBoundaryNodes ) {
3330       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3331       map< SMESH_TLink, int >::iterator link_nb;
3332       // put all elements links to linkNbMap
3333       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3334       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3335         const SMDS_MeshElement* elem = (*elemIt);
3336         int nbn =  elem->NbCornerNodes();
3337         // loop on elem links: insert them in linkNbMap
3338         for ( int iN = 0; iN < nbn; ++iN ) {
3339           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3340           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3341           SMESH_TLink link( n1, n2 );
3342           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3343           link_nb->second++;
3344         }
3345       }
3346       // remove nodes that are in links encountered only once from setMovableNodes
3347       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3348         if ( link_nb->second == 1 ) {
3349           setMovableNodes.erase( link_nb->first.node1() );
3350           setMovableNodes.erase( link_nb->first.node2() );
3351         }
3352       }
3353     }
3354
3355     // -----------------------------------------------------
3356     // for nodes on seam edge, compute one more UV ( uvMap2 );
3357     // find movable nodes linked to nodes on seam and which
3358     // are to be smoothed using the second UV ( uvMap2 )
3359     // -----------------------------------------------------
3360
3361     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3362     if ( !surface.IsNull() ) {
3363       TopExp_Explorer eExp( face, TopAbs_EDGE );
3364       for ( ; eExp.More(); eExp.Next() ) {
3365         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3366         if ( !BRep_Tool::IsClosed( edge, face ))
3367           continue;
3368         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3369         if ( !sm ) continue;
3370         // find out which parameter varies for a node on seam
3371         double f,l;
3372         gp_Pnt2d uv1, uv2;
3373         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3374         if ( pcurve.IsNull() ) continue;
3375         uv1 = pcurve->Value( f );
3376         edge.Reverse();
3377         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3378         if ( pcurve.IsNull() ) continue;
3379         uv2 = pcurve->Value( f );
3380         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3381         // assure uv1 < uv2
3382         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3383           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3384         }
3385         // get nodes on seam and its vertices
3386         list< const SMDS_MeshNode* > seamNodes;
3387         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3388         while ( nSeamIt->more() ) {
3389           const SMDS_MeshNode* node = nSeamIt->next();
3390           if ( !isQuadratic || !IsMedium( node ))
3391             seamNodes.push_back( node );
3392         }
3393         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3394         for ( ; vExp.More(); vExp.Next() ) {
3395           sm = aMesh->MeshElements( vExp.Current() );
3396           if ( sm ) {
3397             nSeamIt = sm->GetNodes();
3398             while ( nSeamIt->more() )
3399               seamNodes.push_back( nSeamIt->next() );
3400           }
3401         }
3402         // loop on nodes on seam
3403         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3404         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3405           const SMDS_MeshNode* nSeam = *noSeIt;
3406           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3407           if ( n_uv == uvMap.end() )
3408             continue;
3409           // set the first UV
3410           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3411           // set the second UV
3412           listUV.push_back( *n_uv->second );
3413           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3414           if ( uvMap2.empty() )
3415             uvMap2 = uvMap; // copy the uvMap contents
3416           uvMap2[ nSeam ] = &listUV.back();
3417
3418           // collect movable nodes linked to ones on seam in nodesNearSeam
3419           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3420           while ( eIt->more() ) {
3421             const SMDS_MeshElement* e = eIt->next();
3422             int nbUseMap1 = 0, nbUseMap2 = 0;
3423             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3424             int nn = 0, nbn =  e->NbNodes();
3425             if(e->IsQuadratic()) nbn = nbn/2;
3426             while ( nn++ < nbn )
3427             {
3428               const SMDS_MeshNode* n =
3429                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3430               if (n == nSeam ||
3431                   setMovableNodes.find( n ) == setMovableNodes.end() )
3432                 continue;
3433               // add only nodes being closer to uv2 than to uv1
3434               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3435                            0.5 * ( n->Y() + nSeam->Y() ),
3436                            0.5 * ( n->Z() + nSeam->Z() ));
3437               gp_XY uv;
3438               getClosestUV( projector, pMid, uv );
3439               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3440                 nodesNearSeam.insert( n );
3441                 nbUseMap2++;
3442               }
3443               else
3444                 nbUseMap1++;
3445             }
3446             // for centroidalSmooth all element nodes must
3447             // be on one side of a seam
3448             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3449               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3450               nn = 0;
3451               while ( nn++ < nbn ) {
3452                 const SMDS_MeshNode* n =
3453                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3454                 setMovableNodes.erase( n );
3455               }
3456             }
3457           }
3458         } // loop on nodes on seam
3459       } // loop on edge of a face
3460     } // if ( !face.IsNull() )
3461
3462     if ( setMovableNodes.empty() ) {
3463       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3464       continue; // goto next face
3465     }
3466
3467     // -------------
3468     // SMOOTHING //
3469     // -------------
3470
3471     int it = -1;
3472     double maxRatio = -1., maxDisplacement = -1.;
3473     set<const SMDS_MeshNode*>::iterator nodeToMove;
3474     for ( it = 0; it < theNbIterations; it++ ) {
3475       maxDisplacement = 0.;
3476       nodeToMove = setMovableNodes.begin();
3477       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3478         const SMDS_MeshNode* node = (*nodeToMove);
3479         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3480
3481         // smooth
3482         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3483         if ( theSmoothMethod == LAPLACIAN )
3484           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3485         else
3486           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3487
3488         // node displacement
3489         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3490         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3491         if ( aDispl > maxDisplacement )
3492           maxDisplacement = aDispl;
3493       }
3494       // no node movement => exit
3495       //if ( maxDisplacement < 1.e-16 ) {
3496       if ( maxDisplacement < disttol ) {
3497         MESSAGE("-- no node movement --");
3498         break;
3499       }
3500
3501       // check elements quality
3502       maxRatio  = 0;
3503       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3504       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3505         const SMDS_MeshElement* elem = (*elemIt);
3506         if ( !elem || elem->GetType() != SMDSAbs_Face )
3507           continue;
3508         SMESH::Controls::TSequenceOfXYZ aPoints;
3509         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3510           double aValue = aQualityFunc.GetValue( aPoints );
3511           if ( aValue > maxRatio )
3512             maxRatio = aValue;
3513         }
3514       }
3515       if ( maxRatio <= theTgtAspectRatio ) {
3516         MESSAGE("-- quality achived --");
3517         break;
3518       }
3519       if (it+1 == theNbIterations) {
3520         MESSAGE("-- Iteration limit exceeded --");
3521       }
3522     } // smoothing iterations
3523
3524     MESSAGE(" Face id: " << *fId <<
3525             " Nb iterstions: " << it <<
3526             " Displacement: " << maxDisplacement <<
3527             " Aspect Ratio " << maxRatio);
3528
3529     // ---------------------------------------
3530     // new nodes positions are computed,
3531     // record movement in DS and set new UV
3532     // ---------------------------------------
3533     nodeToMove = setMovableNodes.begin();
3534     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3535       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3536       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3537       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3538       if ( node_uv != uvMap.end() ) {
3539         gp_XY* uv = node_uv->second;
3540         node->SetPosition
3541           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3542       }
3543     }
3544
3545     // move medium nodes of quadratic elements
3546     if ( isQuadratic )
3547     {
3548       SMESH_MesherHelper helper( *GetMesh() );
3549       helper.SetSubShape( face );
3550       vector<const SMDS_MeshNode*> nodes;
3551       bool checkUV;
3552       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3553       for ( ; elemIt != elemsOnFace.end(); ++elemIt )
3554       {
3555         const SMDS_MeshElement* QF = *elemIt;
3556         if ( QF->IsQuadratic() )
3557         {
3558           nodes.assign( SMDS_MeshElement::iterator( QF->interlacedNodesElemIterator() ),
3559                         SMDS_MeshElement::iterator() );
3560           nodes.push_back( nodes[0] );
3561           gp_Pnt xyz;
3562           for (size_t i = 1; i < nodes.size(); i += 2 ) // i points to a medium node
3563           {
3564             if ( !surface.IsNull() )
3565             {
3566               gp_XY uv1 = helper.GetNodeUV( face, nodes[i-1], nodes[i+1], &checkUV );
3567               gp_XY uv2 = helper.GetNodeUV( face, nodes[i+1], nodes[i-1], &checkUV );
3568               gp_XY uv  = helper.GetMiddleUV( surface, uv1, uv2 );
3569               xyz = surface->Value( uv.X(), uv.Y() );
3570             }
3571             else {
3572               xyz = 0.5 * ( SMESH_TNodeXYZ( nodes[i-1] ) + SMESH_TNodeXYZ( nodes[i+1] ));
3573             }
3574             if (( SMESH_TNodeXYZ( nodes[i] ) - xyz.XYZ() ).Modulus() > disttol )
3575               // we have to move a medium node
3576               aMesh->MoveNode( nodes[i], xyz.X(), xyz.Y(), xyz.Z() );
3577           }
3578         }
3579       }
3580     }
3581
3582   } // loop on face ids
3583
3584 }
3585
3586 //=======================================================================
3587 //function : isReverse
3588 //purpose  : Return true if normal of prevNodes is not co-directied with
3589 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3590 //           iNotSame is where prevNodes and nextNodes are different.
3591 //           If result is true then future volume orientation is OK
3592 //=======================================================================
3593
3594 static bool isReverse(const SMDS_MeshElement*             face,
3595                       const vector<const SMDS_MeshNode*>& prevNodes,
3596                       const vector<const SMDS_MeshNode*>& nextNodes,
3597                       const int                           iNotSame)
3598 {
3599
3600   SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
3601   SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
3602   gp_XYZ extrDir( pN - pP ), faceNorm;
3603   SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false );
3604
3605   return faceNorm * extrDir < 0.0;
3606 }
3607
3608 //=======================================================================
3609 /*!
3610  * \brief Create elements by sweeping an element
3611  * \param elem - element to sweep
3612  * \param newNodesItVec - nodes generated from each node of the element
3613  * \param newElems - generated elements
3614  * \param nbSteps - number of sweeping steps
3615  * \param srcElements - to append elem for each generated element
3616  */
3617 //=======================================================================
3618
3619 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3620                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3621                                     list<const SMDS_MeshElement*>&        newElems,
3622                                     const int                             nbSteps,
3623                                     SMESH_SequenceOfElemPtr&              srcElements)
3624 {
3625   //MESSAGE("sweepElement " << nbSteps);
3626   SMESHDS_Mesh* aMesh = GetMeshDS();
3627
3628   const int           nbNodes = elem->NbNodes();
3629   const int         nbCorners = elem->NbCornerNodes();
3630   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of
3631                                                           polyhedron creation !!! */
3632   // Loop on elem nodes:
3633   // find new nodes and detect same nodes indices
3634   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3635   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3636   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3637   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3638
3639   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
3640   vector<int> sames(nbNodes);
3641   vector<bool> isSingleNode(nbNodes);
3642
3643   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3644     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
3645     const SMDS_MeshNode*                         node = nnIt->first;
3646     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3647     if ( listNewNodes.empty() )
3648       return;
3649
3650     itNN   [ iNode ] = listNewNodes.begin();
3651     prevNod[ iNode ] = node;
3652     nextNod[ iNode ] = listNewNodes.front();
3653
3654     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
3655                                                              corner node of linear */
3656     if ( prevNod[ iNode ] != nextNod [ iNode ])
3657       nbDouble += !isSingleNode[iNode];
3658
3659     if( iNode < nbCorners ) { // check corners only
3660       if ( prevNod[ iNode ] == nextNod [ iNode ])
3661         sames[nbSame++] = iNode;
3662       else
3663         iNotSameNode = iNode;
3664     }
3665   }
3666
3667   if ( nbSame == nbNodes || nbSame > 2) {
3668     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3669     return;
3670   }
3671
3672   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
3673   {
3674     // fix nodes order to have bottom normal external
3675     if ( baseType == SMDSEntity_Polygon )
3676     {
3677       std::reverse( itNN.begin(), itNN.end() );
3678       std::reverse( prevNod.begin(), prevNod.end() );
3679       std::reverse( midlNod.begin(), midlNod.end() );
3680       std::reverse( nextNod.begin(), nextNod.end() );
3681       std::reverse( isSingleNode.begin(), isSingleNode.end() );
3682     }
3683     else
3684     {
3685       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
3686       SMDS_MeshCell::applyInterlace( ind, itNN );
3687       SMDS_MeshCell::applyInterlace( ind, prevNod );
3688       SMDS_MeshCell::applyInterlace( ind, nextNod );
3689       SMDS_MeshCell::applyInterlace( ind, midlNod );
3690       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3691       if ( nbSame > 0 )
3692       {
3693         sames[nbSame] = iNotSameNode;
3694         for ( int j = 0; j <= nbSame; ++j )
3695           for ( size_t i = 0; i < ind.size(); ++i )
3696             if ( ind[i] == sames[j] )
3697             {
3698               sames[j] = i;
3699               break;
3700             }
3701         iNotSameNode = sames[nbSame];
3702       }
3703     }
3704   }
3705
3706   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3707   if ( nbSame > 0 ) {
3708     iSameNode    = sames[ nbSame-1 ];
3709     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
3710     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
3711     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3712   }
3713
3714   // make new elements
3715   for (int iStep = 0; iStep < nbSteps; iStep++ )
3716   {
3717     // get next nodes
3718     for ( iNode = 0; iNode < nbNodes; iNode++ )
3719     {
3720       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
3721       nextNod[ iNode ] = *itNN[ iNode ]++;
3722     }
3723
3724     SMDS_MeshElement* aNewElem = 0;
3725     /*if(!elem->IsPoly())*/ {
3726       switch ( baseType ) {
3727       case SMDSEntity_0D:
3728       case SMDSEntity_Node: { // sweep NODE
3729         if ( nbSame == 0 ) {
3730           if ( isSingleNode[0] )
3731             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3732           else
3733             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3734         }
3735         else
3736           return;
3737         break;
3738       }
3739       case SMDSEntity_Edge: { // sweep EDGE
3740         if ( nbDouble == 0 )
3741         {
3742           if ( nbSame == 0 ) // ---> quadrangle
3743             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3744                                       nextNod[ 1 ], nextNod[ 0 ] );
3745           else               // ---> triangle
3746             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3747                                       nextNod[ iNotSameNode ] );
3748         }
3749         else                 // ---> polygon
3750         {
3751           vector<const SMDS_MeshNode*> poly_nodes;
3752           poly_nodes.push_back( prevNod[0] );
3753           poly_nodes.push_back( prevNod[1] );
3754           if ( prevNod[1] != nextNod[1] )
3755           {
3756             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
3757             poly_nodes.push_back( nextNod[1] );
3758           }
3759           if ( prevNod[0] != nextNod[0] )
3760           {
3761             poly_nodes.push_back( nextNod[0] );
3762             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
3763           }
3764           switch ( poly_nodes.size() ) {
3765           case 3:
3766             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
3767             break;
3768           case 4:
3769             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
3770                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
3771             break;
3772           default:
3773             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
3774           }
3775         }
3776         break;
3777       }
3778       case SMDSEntity_Triangle: // TRIANGLE --->
3779         {
3780           if ( nbDouble > 0 ) break;
3781           if ( nbSame == 0 )       // ---> pentahedron
3782             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3783                                          nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
3784
3785           else if ( nbSame == 1 )  // ---> pyramid
3786             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3787                                          nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3788                                          nextNod[ iSameNode ]);
3789
3790           else // 2 same nodes:       ---> tetrahedron
3791             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3792                                          nextNod[ iNotSameNode ]);
3793           break;
3794         }
3795       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
3796         {
3797           if ( nbSame == 2 )
3798             return;
3799           if ( nbDouble+nbSame == 2 )
3800           {
3801             if(nbSame==0) {      // ---> quadratic quadrangle
3802               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3803                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
3804             }
3805             else { //(nbSame==1) // ---> quadratic triangle
3806               if(sames[0]==2) {
3807                 return; // medium node on axis
3808               }
3809               else if(sames[0]==0)
3810                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3811                                           nextNod[2], midlNod[1], prevNod[2]);
3812               else // sames[0]==1
3813                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3814                                           midlNod[0], nextNod[2], prevNod[2]);
3815             }
3816           }
3817           else if ( nbDouble == 3 )
3818           {
3819             if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
3820               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3821                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
3822             }
3823           }
3824           else
3825             return;
3826           break;
3827         }
3828       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
3829         if ( nbDouble > 0 ) break;
3830
3831         if ( nbSame == 0 )       // ---> hexahedron
3832           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
3833                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
3834
3835         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
3836           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3837                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3838                                        nextNod[ iSameNode ]);
3839           newElems.push_back( aNewElem );
3840           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
3841                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3842                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3843         }
3844         else if ( nbSame == 2 ) { // ---> pentahedron
3845           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3846             // iBeforeSame is same too
3847             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3848                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
3849                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3850           else
3851             // iAfterSame is same too
3852             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
3853                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3854                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3855         }
3856         break;
3857       }
3858       case SMDSEntity_Quad_Triangle:  // sweep (Bi)Quadratic TRIANGLE --->
3859       case SMDSEntity_BiQuad_Triangle: /* ??? */ { 
3860         if ( nbDouble+nbSame != 3 ) break;
3861         if(nbSame==0) {
3862           // --->  pentahedron with 15 nodes
3863           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3864                                        nextNod[0], nextNod[1], nextNod[2],
3865                                        prevNod[3], prevNod[4], prevNod[5],
3866                                        nextNod[3], nextNod[4], nextNod[5],
3867                                        midlNod[0], midlNod[1], midlNod[2]);
3868         }
3869         else if(nbSame==1) {
3870           // --->  2d order pyramid of 13 nodes
3871           int apex = iSameNode;
3872           int i0 = ( apex + 1 ) % nbCorners;
3873           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
3874           int i0a = apex + 3;
3875           int i1a = i1 + 3;
3876           int i01 = i0 + 3;
3877           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
3878                                       nextNod[i0], nextNod[i1], prevNod[apex],
3879                                       prevNod[i01], midlNod[i0],
3880                                       nextNod[i01], midlNod[i1],
3881                                       prevNod[i1a], prevNod[i0a],
3882                                       nextNod[i0a], nextNod[i1a]);
3883         }
3884         else if(nbSame==2) {
3885           // --->  2d order tetrahedron of 10 nodes
3886           int n1 = iNotSameNode;
3887           int n2 = ( n1 + 1             ) % nbCorners;
3888           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
3889           int n12 = n1 + 3;
3890           int n23 = n2 + 3;
3891           int n31 = n3 + 3;
3892           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3893                                        prevNod[n12], prevNod[n23], prevNod[n31],
3894                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3895         }
3896         break;
3897       }
3898       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
3899         if( nbSame == 0 ) {
3900           if ( nbDouble != 4 ) break;
3901           // --->  hexahedron with 20 nodes
3902           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3903                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3904                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3905                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3906                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3907         }
3908         else if(nbSame==1) {
3909           // ---> pyramid + pentahedron - can not be created since it is needed
3910           // additional middle node at the center of face
3911           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3912           return;
3913         }
3914         else if( nbSame == 2 ) {
3915           if ( nbDouble != 2 ) break;
3916           // --->  2d order Pentahedron with 15 nodes
3917           int n1,n2,n4,n5;
3918           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3919             // iBeforeSame is same too
3920             n1 = iBeforeSame;
3921             n2 = iOpposSame;
3922             n4 = iSameNode;
3923             n5 = iAfterSame;
3924           }
3925           else {
3926             // iAfterSame is same too
3927             n1 = iSameNode;
3928             n2 = iBeforeSame;
3929             n4 = iAfterSame;
3930             n5 = iOpposSame;
3931           }
3932           int n12 = n2 + 4;
3933           int n45 = n4 + 4;
3934           int n14 = n1 + 4;
3935           int n25 = n5 + 4;
3936           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3937                                        prevNod[n4], prevNod[n5], nextNod[n5],
3938                                        prevNod[n12], midlNod[n2], nextNod[n12],
3939                                        prevNod[n45], midlNod[n5], nextNod[n45],
3940                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3941         }
3942         break;
3943       }
3944       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
3945
3946         if( nbSame == 0 && nbDouble == 9 ) {
3947           // --->  tri-quadratic hexahedron with 27 nodes
3948           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3949                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3950                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3951                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3952                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
3953                                        prevNod[8], // bottom center
3954                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
3955                                        nextNod[8], // top center
3956                                        midlNod[8]);// elem center
3957         }
3958         else
3959         {
3960           return;
3961         }
3962         break;
3963       }
3964       case SMDSEntity_Polygon: { // sweep POLYGON
3965
3966         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
3967           // --->  hexagonal prism
3968           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3969                                        prevNod[3], prevNod[4], prevNod[5],
3970                                        nextNod[0], nextNod[1], nextNod[2],
3971                                        nextNod[3], nextNod[4], nextNod[5]);
3972         }
3973         break;
3974       }
3975       case SMDSEntity_Ball:
3976         return;
3977
3978       default:
3979         break;
3980       }
3981     }
3982
3983     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
3984     {
3985       if ( baseType != SMDSEntity_Polygon )
3986       {
3987         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
3988         SMDS_MeshCell::applyInterlace( ind, prevNod );
3989         SMDS_MeshCell::applyInterlace( ind, nextNod );
3990         SMDS_MeshCell::applyInterlace( ind, midlNod );
3991         SMDS_MeshCell::applyInterlace( ind, itNN );
3992         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3993         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
3994       }
3995       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3996       vector<int> quantities (nbNodes + 2);
3997       polyedre_nodes.clear();
3998       quantities.clear();
3999
4000       // bottom of prism
4001       for (int inode = 0; inode < nbNodes; inode++)
4002         polyedre_nodes.push_back( prevNod[inode] );
4003       quantities.push_back( nbNodes );
4004
4005       // top of prism
4006       polyedre_nodes.push_back( nextNod[0] );
4007       for (int inode = nbNodes; inode-1; --inode )
4008         polyedre_nodes.push_back( nextNod[inode-1] );
4009       quantities.push_back( nbNodes );
4010
4011       // side faces
4012       for (int iface = 0; iface < nbNodes; iface++)
4013       {
4014         const int prevNbNodes = polyedre_nodes.size();
4015         int inextface = (iface+1) % nbNodes;
4016         polyedre_nodes.push_back( prevNod[inextface] );
4017         polyedre_nodes.push_back( prevNod[iface] );
4018         if ( prevNod[iface] != nextNod[iface] )
4019         {
4020           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
4021           polyedre_nodes.push_back( nextNod[iface] );
4022         }
4023         if ( prevNod[inextface] != nextNod[inextface] )
4024         {
4025           polyedre_nodes.push_back( nextNod[inextface] );
4026           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
4027         }
4028         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
4029         if ( nbFaceNodes > 2 )
4030           quantities.push_back( nbFaceNodes );
4031         else // degenerated face
4032           polyedre_nodes.resize( prevNbNodes );
4033       }
4034       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
4035     }
4036
4037     if ( aNewElem ) {
4038       newElems.push_back( aNewElem );
4039       myLastCreatedElems.Append(aNewElem);
4040       srcElements.Append( elem );
4041     }
4042
4043     // set new prev nodes
4044     for ( iNode = 0; iNode < nbNodes; iNode++ )
4045       prevNod[ iNode ] = nextNod[ iNode ];
4046
4047   } // for steps
4048 }
4049
4050 //=======================================================================
4051 /*!
4052  * \brief Create 1D and 2D elements around swept elements
4053  * \param mapNewNodes - source nodes and ones generated from them
4054  * \param newElemsMap - source elements and ones generated from them
4055  * \param elemNewNodesMap - nodes generated from each node of each element
4056  * \param elemSet - all swept elements
4057  * \param nbSteps - number of sweeping steps
4058  * \param srcElements - to append elem for each generated element
4059  */
4060 //=======================================================================
4061
4062 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
4063                                   TElemOfElemListMap &     newElemsMap,
4064                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
4065                                   TIDSortedElemSet&        elemSet,
4066                                   const int                nbSteps,
4067                                   SMESH_SequenceOfElemPtr& srcElements)
4068 {
4069   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
4070   SMESHDS_Mesh* aMesh = GetMeshDS();
4071
4072   // Find nodes belonging to only one initial element - sweep them into edges.
4073
4074   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
4075   for ( ; nList != mapNewNodes.end(); nList++ )
4076   {
4077     const SMDS_MeshNode* node =
4078       static_cast<const SMDS_MeshNode*>( nList->first );
4079     if ( newElemsMap.count( node ))
4080       continue; // node was extruded into edge
4081     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
4082     int nbInitElems = 0;
4083     const SMDS_MeshElement* el = 0;
4084     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
4085     while ( eIt->more() && nbInitElems < 2 ) {
4086       el = eIt->next();
4087       SMDSAbs_ElementType type = el->GetType();
4088       if ( type == SMDSAbs_Volume || type < highType ) continue;
4089       if ( type > highType ) {
4090         nbInitElems = 0;
4091         highType = type;
4092       }
4093       nbInitElems += elemSet.count(el);
4094     }
4095     if ( nbInitElems < 2 ) {
4096       bool NotCreateEdge = el && el->IsMediumNode(node);
4097       if(!NotCreateEdge) {
4098         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
4099         list<const SMDS_MeshElement*> newEdges;
4100         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
4101       }
4102     }
4103   }
4104
4105   // Make a ceiling for each element ie an equal element of last new nodes.
4106   // Find free links of faces - make edges and sweep them into faces.
4107
4108   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
4109   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
4110   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
4111   {
4112     const SMDS_MeshElement* elem = itElem->first;
4113     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
4114
4115     if(itElem->second.size()==0) continue;
4116
4117     const bool isQuadratic = elem->IsQuadratic();
4118
4119     if ( elem->GetType() == SMDSAbs_Edge ) {
4120       // create a ceiling edge
4121       if ( !isQuadratic ) {
4122         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4123                                vecNewNodes[ 1 ]->second.back())) {
4124           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4125                                                    vecNewNodes[ 1 ]->second.back()));
4126           srcElements.Append( elem );
4127         }
4128       }
4129       else {
4130         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4131                                vecNewNodes[ 1 ]->second.back(),
4132                                vecNewNodes[ 2 ]->second.back())) {
4133           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4134                                                    vecNewNodes[ 1 ]->second.back(),
4135                                                    vecNewNodes[ 2 ]->second.back()));
4136           srcElements.Append( elem );
4137         }
4138       }
4139     }
4140     if ( elem->GetType() != SMDSAbs_Face )
4141       continue;
4142
4143     bool hasFreeLinks = false;
4144
4145     TIDSortedElemSet avoidSet;
4146     avoidSet.insert( elem );
4147
4148     set<const SMDS_MeshNode*> aFaceLastNodes;
4149     int iNode, nbNodes = vecNewNodes.size();
4150     if ( !isQuadratic ) {
4151       // loop on the face nodes
4152       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4153         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4154         // look for free links of the face
4155         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4156         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4157         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4158         // check if a link n1-n2 is free
4159         if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4160           hasFreeLinks = true;
4161           // make a new edge and a ceiling for a new edge
4162           const SMDS_MeshElement* edge;
4163           if ( ! ( edge = aMesh->FindEdge( n1, n2 ))) {
4164             myLastCreatedElems.Append( edge = aMesh->AddEdge( n1, n2 )); // free link edge
4165             srcElements.Append( myLastCreatedElems.Last() );
4166           }
4167           n1 = vecNewNodes[ iNode ]->second.back();
4168           n2 = vecNewNodes[ iNext ]->second.back();
4169           if ( !aMesh->FindEdge( n1, n2 )) {
4170             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling
4171             srcElements.Append( edge );
4172           }
4173         }
4174       }
4175     }
4176     else { // elem is quadratic face
4177       int nbn = nbNodes/2;
4178       for ( iNode = 0; iNode < nbn; iNode++ ) {
4179         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4180         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4181         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4182         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4183         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4184         // check if a link is free
4185         if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4186              ! SMESH_MeshAlgos::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4187              ! SMESH_MeshAlgos::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4188           hasFreeLinks = true;
4189           // make an edge and a ceiling for a new edge
4190           // find medium node
4191           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4192             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4193             srcElements.Append( elem );
4194           }
4195           n1 = vecNewNodes[ iNode ]->second.back();
4196           n2 = vecNewNodes[ iNext ]->second.back();
4197           n3 = vecNewNodes[ iNode+nbn ]->second.back();
4198           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4199             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4200             srcElements.Append( elem );
4201           }
4202         }
4203       }
4204       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4205         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4206       }
4207     }
4208
4209     // sweep free links into faces
4210
4211     if ( hasFreeLinks )  {
4212       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4213       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4214
4215       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4216       set<const SMDS_MeshNode*> initNodeSetNoCenter/*, topNodeSetNoCenter*/;
4217       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4218         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4219         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4220       }
4221       if ( isQuadratic && nbNodes % 2 ) {  // node set for the case of a biquadratic
4222         initNodeSetNoCenter = initNodeSet; // swept face and a not biquadratic volume
4223         initNodeSetNoCenter.erase( vecNewNodes.back()->first );
4224       }
4225       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4226         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4227         std::advance( v, volNb );
4228         // find indices of free faces of a volume and their source edges
4229         list< int > freeInd;
4230         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4231         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4232         int iF, nbF = vTool.NbFaces();
4233         for ( iF = 0; iF < nbF; iF ++ ) {
4234           if (vTool.IsFreeFace( iF ) &&
4235               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4236               initNodeSet != faceNodeSet) // except an initial face
4237           {
4238             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4239               continue;
4240             if ( faceNodeSet == initNodeSetNoCenter )
4241               continue;
4242             freeInd.push_back( iF );
4243             // find source edge of a free face iF
4244             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4245             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4246             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4247                                    initNodeSet.begin(), initNodeSet.end(),
4248                                    commonNodes.begin());
4249             if ( (*v)->IsQuadratic() )
4250               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4251             else
4252               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4253 #ifdef _DEBUG_
4254             if ( !srcEdges.back() )
4255             {
4256               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4257                    << iF << " of volume #" << vTool.ID() << endl;
4258             }
4259 #endif
4260           }
4261         }
4262         if ( freeInd.empty() )
4263           continue;
4264
4265         // create faces for all steps;
4266         // if such a face has been already created by sweep of edge,
4267         // assure that its orientation is OK
4268         for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4269           vTool.Set( *v, /*ignoreCentralNodes=*/false );
4270           vTool.SetExternalNormal();
4271           const int nextShift = vTool.IsForward() ? +1 : -1;
4272           list< int >::iterator ind = freeInd.begin();
4273           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4274           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4275           {
4276             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4277             int nbn = vTool.NbFaceNodes( *ind );
4278             const SMDS_MeshElement * f = 0;
4279             if ( nbn == 3 )              ///// triangle
4280             {
4281               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4282               if ( !f ||
4283                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4284               {
4285                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4286                                                      nodes[ 1 ],
4287                                                      nodes[ 1 + nextShift ] };
4288                 if ( f )
4289                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4290                 else
4291                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4292                                                             newOrder[ 2 ] ));
4293               }
4294             }
4295             else if ( nbn == 4 )       ///// quadrangle
4296             {
4297               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4298               if ( !f ||
4299                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4300               {
4301                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4302                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
4303                 if ( f )
4304                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4305                 else
4306                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4307                                                             newOrder[ 2 ], newOrder[ 3 ]));
4308               }
4309             }
4310             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4311             {
4312               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4313               if ( !f ||
4314                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4315               {
4316                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4317                                                      nodes[2],
4318                                                      nodes[2 + 2*nextShift],
4319                                                      nodes[3 - 2*nextShift],
4320                                                      nodes[3],
4321                                                      nodes[3 + 2*nextShift]};
4322                 if ( f )
4323                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4324                 else
4325                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4326                                                             newOrder[ 1 ],
4327                                                             newOrder[ 2 ],
4328                                                             newOrder[ 3 ],
4329                                                             newOrder[ 4 ],
4330                                                             newOrder[ 5 ] ));
4331               }
4332             }
4333             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4334             {
4335               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4336                                    nodes[1], nodes[3], nodes[5], nodes[7] );
4337               if ( !f ||
4338                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4339               {
4340                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4341                                                      nodes[4 - 2*nextShift],
4342                                                      nodes[4],
4343                                                      nodes[4 + 2*nextShift],
4344                                                      nodes[1],
4345                                                      nodes[5 - 2*nextShift],
4346                                                      nodes[5],
4347                                                      nodes[5 + 2*nextShift] };
4348                 if ( f )
4349                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4350                 else
4351                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4352                                                            newOrder[ 2 ], newOrder[ 3 ],
4353                                                            newOrder[ 4 ], newOrder[ 5 ],
4354                                                            newOrder[ 6 ], newOrder[ 7 ]));
4355               }
4356             }
4357             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4358             {
4359               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4360                                       SMDSAbs_Face, /*noMedium=*/false);
4361               if ( !f ||
4362                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4363               {
4364                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
4365                                                      nodes[4 - 2*nextShift],
4366                                                      nodes[4],
4367                                                      nodes[4 + 2*nextShift],
4368                                                      nodes[1],
4369                                                      nodes[5 - 2*nextShift],
4370                                                      nodes[5],
4371                                                      nodes[5 + 2*nextShift],
4372                                                      nodes[8] };
4373                 if ( f )
4374                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4375                 else
4376                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4377                                                            newOrder[ 2 ], newOrder[ 3 ],
4378                                                            newOrder[ 4 ], newOrder[ 5 ],
4379                                                            newOrder[ 6 ], newOrder[ 7 ],
4380                                                            newOrder[ 8 ]));
4381               }
4382             }
4383             else  //////// polygon
4384             {
4385               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
4386               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4387               if ( !f ||
4388                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4389               {
4390                 if ( !vTool.IsForward() )
4391                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4392                 if ( f )
4393                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4394                 else
4395                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4396               }
4397             }
4398
4399             while ( srcElements.Length() < myLastCreatedElems.Length() )
4400               srcElements.Append( *srcEdge );
4401
4402           }  // loop on free faces
4403
4404           // go to the next volume
4405           iVol = 0;
4406           while ( iVol++ < nbVolumesByStep ) v++;
4407
4408         } // loop on steps
4409       } // loop on volumes of one step
4410     } // sweep free links into faces
4411
4412     // Make a ceiling face with a normal external to a volume
4413
4414     // use SMDS_VolumeTool to get a correctly ordered nodes of a ceiling face
4415     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
4416     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4417
4418     if ( iF < 0 && isQuadratic && nbNodes % 2 ) { // remove a central node of biquadratic
4419       aFaceLastNodes.erase( vecNewNodes.back()->second.back() );
4420       iF = lastVol.GetFaceIndex( aFaceLastNodes );
4421     }
4422     if ( iF >= 0 ) {
4423       lastVol.SetExternalNormal();
4424       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4425       int nbn = lastVol.NbFaceNodes( iF );
4426       // we do not use this->AddElement() because nodes are interlaced
4427       vector<const SMDS_MeshNode*> nodeVec( nodes, nodes+nbn );
4428       if ( !hasFreeLinks ||
4429            !aMesh->FindElement( nodeVec, SMDSAbs_Face, /*noMedium=*/false) )
4430       {
4431         if ( nbn == 3 )
4432           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2] ));
4433
4434         else if ( nbn == 4 )
4435           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2], nodes[3]));
4436
4437         else if ( nbn == 6 && isQuadratic )
4438           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4],
4439                                                     nodes[1], nodes[3], nodes[5]));
4440         else if ( nbn == 7 && isQuadratic )
4441           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4],
4442                                                     nodes[1], nodes[3], nodes[5], nodes[6]));
4443         else if ( nbn == 8 && isQuadratic )
4444           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], nodes[6],
4445                                                     nodes[1], nodes[3], nodes[5], nodes[7]));
4446         else if ( nbn == 9 && isQuadratic )
4447           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], nodes[6],
4448                                                     nodes[1], nodes[3], nodes[5], nodes[7],
4449                                                     nodes[8]));
4450         else
4451           myLastCreatedElems.Append(aMesh->AddPolygonalFace( nodeVec ));
4452
4453         while ( srcElements.Length() < myLastCreatedElems.Length() )
4454           srcElements.Append( elem );
4455       }
4456     }
4457   } // loop on swept elements
4458 }
4459
4460 //=======================================================================
4461 //function : RotationSweep
4462 //purpose  :
4463 //=======================================================================
4464
4465 SMESH_MeshEditor::PGroupIDs
4466 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4467                                 const gp_Ax1&      theAxis,
4468                                 const double       theAngle,
4469                                 const int          theNbSteps,
4470                                 const double       theTol,
4471                                 const bool         theMakeGroups,
4472                                 const bool         theMakeWalls)
4473 {
4474   myLastCreatedElems.Clear();
4475   myLastCreatedNodes.Clear();
4476
4477   // source elements for each generated one
4478   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4479
4480   MESSAGE( "RotationSweep()");
4481   gp_Trsf aTrsf;
4482   aTrsf.SetRotation( theAxis, theAngle );
4483   gp_Trsf aTrsf2;
4484   aTrsf2.SetRotation( theAxis, theAngle/2. );
4485
4486   gp_Lin aLine( theAxis );
4487   double aSqTol = theTol * theTol;
4488
4489   SMESHDS_Mesh* aMesh = GetMeshDS();
4490
4491   TNodeOfNodeListMap mapNewNodes;
4492   TElemOfVecOfNnlmiMap mapElemNewNodes;
4493   TElemOfElemListMap newElemsMap;
4494
4495   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4496                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4497                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4498   // loop on theElems
4499   TIDSortedElemSet::iterator itElem;
4500   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4501     const SMDS_MeshElement* elem = *itElem;
4502     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4503       continue;
4504     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4505     newNodesItVec.reserve( elem->NbNodes() );
4506
4507     // loop on elem nodes
4508     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4509     while ( itN->more() )
4510     {
4511       // check if a node has been already sweeped
4512       const SMDS_MeshNode* node = cast2Node( itN->next() );
4513
4514       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4515       double coord[3];
4516       aXYZ.Coord( coord[0], coord[1], coord[2] );
4517       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4518
4519       TNodeOfNodeListMapItr nIt =
4520         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4521       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4522       if ( listNewNodes.empty() )
4523       {
4524         // check if we are to create medium nodes between corner ones
4525         bool needMediumNodes = false;
4526         if ( isQuadraticMesh )
4527         {
4528           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4529           while (it->more() && !needMediumNodes )
4530           {
4531             const SMDS_MeshElement* invElem = it->next();
4532             if ( invElem != elem && !theElems.count( invElem )) continue;
4533             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4534             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4535               needMediumNodes = true;
4536           }
4537         }
4538
4539         // make new nodes
4540         const SMDS_MeshNode * newNode = node;
4541         for ( int i = 0; i < theNbSteps; i++ ) {
4542           if ( !isOnAxis ) {
4543             if ( needMediumNodes )  // create a medium node
4544             {
4545               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4546               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4547               myLastCreatedNodes.Append(newNode);
4548               srcNodes.Append( node );
4549               listNewNodes.push_back( newNode );
4550               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4551             }
4552             else {
4553               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4554             }
4555             // create a corner node
4556             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4557             myLastCreatedNodes.Append(newNode);
4558             srcNodes.Append( node );
4559             listNewNodes.push_back( newNode );
4560           }
4561           else {
4562             listNewNodes.push_back( newNode );
4563             // if ( needMediumNodes )
4564             //   listNewNodes.push_back( newNode );
4565           }
4566         }
4567       }
4568       newNodesItVec.push_back( nIt );
4569     }
4570     // make new elements
4571     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4572   }
4573
4574   if ( theMakeWalls )
4575     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4576
4577   PGroupIDs newGroupIDs;
4578   if ( theMakeGroups )
4579     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4580
4581   return newGroupIDs;
4582 }
4583
4584
4585 //=======================================================================
4586 //function : CreateNode
4587 //purpose  :
4588 //=======================================================================
4589 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4590                                                   const double y,
4591                                                   const double z,
4592                                                   const double tolnode,
4593                                                   SMESH_SequenceOfNode& aNodes)
4594 {
4595   // myLastCreatedElems.Clear();
4596   // myLastCreatedNodes.Clear();
4597
4598   gp_Pnt P1(x,y,z);
4599   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4600
4601   // try to search in sequence of existing nodes
4602   // if aNodes.Length()>0 we 'nave to use given sequence
4603   // else - use all nodes of mesh
4604   if(aNodes.Length()>0) {
4605     int i;
4606     for(i=1; i<=aNodes.Length(); i++) {
4607       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4608       if(P1.Distance(P2)<tolnode)
4609         return aNodes.Value(i);
4610     }
4611   }
4612   else {
4613     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4614     while(itn->more()) {
4615       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4616       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4617       if(P1.Distance(P2)<tolnode)
4618         return aN;
4619     }
4620   }
4621
4622   // create new node and return it
4623   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4624   //myLastCreatedNodes.Append(NewNode);
4625   return NewNode;
4626 }
4627
4628
4629 //=======================================================================
4630 //function : ExtrusionSweep
4631 //purpose  :
4632 //=======================================================================
4633
4634 SMESH_MeshEditor::PGroupIDs
4635 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4636                                   const gp_Vec&       theStep,
4637                                   const int           theNbSteps,
4638                                   TElemOfElemListMap& newElemsMap,
4639                                   const bool          theMakeGroups,
4640                                   const int           theFlags,
4641                                   const double        theTolerance)
4642 {
4643   ExtrusParam aParams;
4644   aParams.myDir = gp_Dir(theStep);
4645   aParams.myNodes.Clear();
4646   aParams.mySteps = new TColStd_HSequenceOfReal;
4647   int i;
4648   for(i=1; i<=theNbSteps; i++)
4649     aParams.mySteps->Append(theStep.Magnitude());
4650
4651   return
4652     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4653 }
4654
4655
4656 //=======================================================================
4657 //function : ExtrusionSweep
4658 //purpose  :
4659 //=======================================================================
4660
4661 SMESH_MeshEditor::PGroupIDs
4662 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4663                                   ExtrusParam&        theParams,
4664                                   TElemOfElemListMap& newElemsMap,
4665                                   const bool          theMakeGroups,
4666                                   const int           theFlags,
4667                                   const double        theTolerance)
4668 {
4669   myLastCreatedElems.Clear();
4670   myLastCreatedNodes.Clear();
4671
4672   // source elements for each generated one
4673   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4674
4675   SMESHDS_Mesh* aMesh = GetMeshDS();
4676
4677   int nbsteps = theParams.mySteps->Length();
4678
4679   TNodeOfNodeListMap mapNewNodes;
4680   //TNodeOfNodeVecMap mapNewNodes;
4681   TElemOfVecOfNnlmiMap mapElemNewNodes;
4682   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4683
4684   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4685                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4686                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4687   // loop on theElems
4688   TIDSortedElemSet::iterator itElem;
4689   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4690     // check element type
4691     const SMDS_MeshElement* elem = *itElem;
4692     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4693       continue;
4694
4695     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4696     newNodesItVec.reserve( elem->NbNodes() );
4697
4698     // loop on elem nodes
4699     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4700     while ( itN->more() )
4701     {
4702       // check if a node has been already sweeped
4703       const SMDS_MeshNode* node = cast2Node( itN->next() );
4704       TNodeOfNodeListMap::iterator nIt =
4705         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4706       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4707       if ( listNewNodes.empty() )
4708       {
4709         // make new nodes
4710
4711         // check if we are to create medium nodes between corner ones
4712         bool needMediumNodes = false;
4713         if ( isQuadraticMesh )
4714         {
4715           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4716           while (it->more() && !needMediumNodes )
4717           {
4718             const SMDS_MeshElement* invElem = it->next();
4719             if ( invElem != elem && !theElems.count( invElem )) continue;
4720             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4721             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4722               needMediumNodes = true;
4723           }
4724         }
4725
4726         double coord[] = { node->X(), node->Y(), node->Z() };
4727         for ( int i = 0; i < nbsteps; i++ )
4728         {
4729           if ( needMediumNodes ) // create a medium node
4730           {
4731             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4732             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4733             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4734             if( theFlags & EXTRUSION_FLAG_SEW ) {
4735               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4736                                                          theTolerance, theParams.myNodes);
4737               listNewNodes.push_back( newNode );
4738             }
4739             else {
4740               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4741               myLastCreatedNodes.Append(newNode);
4742               srcNodes.Append( node );
4743               listNewNodes.push_back( newNode );
4744             }
4745           }
4746           // create a corner node
4747           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4748           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4749           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4750           if( theFlags & EXTRUSION_FLAG_SEW ) {
4751             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4752                                                        theTolerance, theParams.myNodes);
4753             listNewNodes.push_back( newNode );
4754           }
4755           else {
4756             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4757             myLastCreatedNodes.Append(newNode);
4758             srcNodes.Append( node );
4759             listNewNodes.push_back( newNode );
4760           }
4761         }
4762       }
4763       newNodesItVec.push_back( nIt );
4764     }
4765     // make new elements
4766     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4767   }
4768
4769   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4770     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4771   }
4772   PGroupIDs newGroupIDs;
4773   if ( theMakeGroups )
4774     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4775
4776   return newGroupIDs;
4777 }
4778
4779 //=======================================================================
4780 //function : ExtrusionAlongTrack
4781 //purpose  :
4782 //=======================================================================
4783 SMESH_MeshEditor::Extrusion_Error
4784 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4785                                        SMESH_subMesh*       theTrack,
4786                                        const SMDS_MeshNode* theN1,
4787                                        const bool           theHasAngles,
4788                                        list<double>&        theAngles,
4789                                        const bool           theLinearVariation,
4790                                        const bool           theHasRefPoint,
4791                                        const gp_Pnt&        theRefPoint,
4792                                        const bool           theMakeGroups)
4793 {
4794   MESSAGE("ExtrusionAlongTrack");
4795   myLastCreatedElems.Clear();
4796   myLastCreatedNodes.Clear();
4797
4798   int aNbE;
4799   std::list<double> aPrms;
4800   TIDSortedElemSet::iterator itElem;
4801
4802   gp_XYZ aGC;
4803   TopoDS_Edge aTrackEdge;
4804   TopoDS_Vertex aV1, aV2;
4805
4806   SMDS_ElemIteratorPtr aItE;
4807   SMDS_NodeIteratorPtr aItN;
4808   SMDSAbs_ElementType aTypeE;
4809
4810   TNodeOfNodeListMap mapNewNodes;
4811
4812   // 1. Check data
4813   aNbE = theElements.size();
4814   // nothing to do
4815   if ( !aNbE )
4816     return EXTR_NO_ELEMENTS;
4817
4818   // 1.1 Track Pattern
4819   ASSERT( theTrack );
4820
4821   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4822
4823   aItE = pSubMeshDS->GetElements();
4824   while ( aItE->more() ) {
4825     const SMDS_MeshElement* pE = aItE->next();
4826     aTypeE = pE->GetType();
4827     // Pattern must contain links only
4828     if ( aTypeE != SMDSAbs_Edge )
4829       return EXTR_PATH_NOT_EDGE;
4830   }
4831
4832   list<SMESH_MeshEditor_PathPoint> fullList;
4833
4834   const TopoDS_Shape& aS = theTrack->GetSubShape();
4835   // Sub-shape for the Pattern must be an Edge or Wire
4836   if( aS.ShapeType() == TopAbs_EDGE ) {
4837     aTrackEdge = TopoDS::Edge( aS );
4838     // the Edge must not be degenerated
4839     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4840       return EXTR_BAD_PATH_SHAPE;
4841     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4842     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4843     const SMDS_MeshNode* aN1 = aItN->next();
4844     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4845     const SMDS_MeshNode* aN2 = aItN->next();
4846     // starting node must be aN1 or aN2
4847     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4848       return EXTR_BAD_STARTING_NODE;
4849     aItN = pSubMeshDS->GetNodes();
4850     while ( aItN->more() ) {
4851       const SMDS_MeshNode* pNode = aItN->next();
4852       const SMDS_EdgePosition* pEPos =
4853         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4854       double aT = pEPos->GetUParameter();
4855       aPrms.push_back( aT );
4856     }
4857     //Extrusion_Error err =
4858     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4859   } else if( aS.ShapeType() == TopAbs_WIRE ) {
4860     list< SMESH_subMesh* > LSM;
4861     TopTools_SequenceOfShape Edges;
4862     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4863     while(itSM->more()) {
4864       SMESH_subMesh* SM = itSM->next();
4865       LSM.push_back(SM);
4866       const TopoDS_Shape& aS = SM->GetSubShape();
4867       Edges.Append(aS);
4868     }
4869     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4870     int startNid = theN1->GetID();
4871     TColStd_MapOfInteger UsedNums;
4872
4873     int NbEdges = Edges.Length();
4874     int i = 1;
4875     for(; i<=NbEdges; i++) {
4876       int k = 0;
4877       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4878       for(; itLSM!=LSM.end(); itLSM++) {
4879         k++;
4880         if(UsedNums.Contains(k)) continue;
4881         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4882         SMESH_subMesh* locTrack = *itLSM;
4883         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4884         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4885         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4886         const SMDS_MeshNode* aN1 = aItN->next();
4887         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4888         const SMDS_MeshNode* aN2 = aItN->next();
4889         // starting node must be aN1 or aN2
4890         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4891         // 2. Collect parameters on the track edge
4892         aPrms.clear();
4893         aItN = locMeshDS->GetNodes();
4894         while ( aItN->more() ) {
4895           const SMDS_MeshNode* pNode = aItN->next();
4896           const SMDS_EdgePosition* pEPos =
4897             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4898           double aT = pEPos->GetUParameter();
4899           aPrms.push_back( aT );
4900         }
4901         list<SMESH_MeshEditor_PathPoint> LPP;
4902         //Extrusion_Error err =
4903         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4904         LLPPs.push_back(LPP);
4905         UsedNums.Add(k);
4906         // update startN for search following egde
4907         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4908         else startNid = aN1->GetID();
4909         break;
4910       }
4911     }
4912     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4913     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4914     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4915     for(; itPP!=firstList.end(); itPP++) {
4916       fullList.push_back( *itPP );
4917     }
4918     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4919     fullList.pop_back();
4920     itLLPP++;
4921     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4922       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4923       itPP = currList.begin();
4924       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4925       gp_Dir D1 = PP1.Tangent();
4926       gp_Dir D2 = PP2.Tangent();
4927       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4928                            (D1.Z()+D2.Z())/2 ) );
4929       PP1.SetTangent(Dnew);
4930       fullList.push_back(PP1);
4931       itPP++;
4932       for(; itPP!=firstList.end(); itPP++) {
4933         fullList.push_back( *itPP );
4934       }
4935       PP1 = fullList.back();
4936       fullList.pop_back();
4937     }
4938     // if wire not closed
4939     fullList.push_back(PP1);
4940     // else ???
4941   }
4942   else {
4943     return EXTR_BAD_PATH_SHAPE;
4944   }
4945
4946   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4947                           theHasRefPoint, theRefPoint, theMakeGroups);
4948 }
4949
4950
4951 //=======================================================================
4952 //function : ExtrusionAlongTrack
4953 //purpose  :
4954 //=======================================================================
4955 SMESH_MeshEditor::Extrusion_Error
4956 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4957                                        SMESH_Mesh*          theTrack,
4958                                        const SMDS_MeshNode* theN1,
4959                                        const bool           theHasAngles,
4960                                        list<double>&        theAngles,
4961                                        const bool           theLinearVariation,
4962                                        const bool           theHasRefPoint,
4963                                        const gp_Pnt&        theRefPoint,
4964                                        const bool           theMakeGroups)
4965 {
4966   myLastCreatedElems.Clear();
4967   myLastCreatedNodes.Clear();
4968
4969   int aNbE;
4970   std::list<double> aPrms;
4971   TIDSortedElemSet::iterator itElem;
4972
4973   gp_XYZ aGC;
4974   TopoDS_Edge aTrackEdge;
4975   TopoDS_Vertex aV1, aV2;
4976
4977   SMDS_ElemIteratorPtr aItE;
4978   SMDS_NodeIteratorPtr aItN;
4979   SMDSAbs_ElementType aTypeE;
4980
4981   TNodeOfNodeListMap mapNewNodes;
4982
4983   // 1. Check data
4984   aNbE = theElements.size();
4985   // nothing to do
4986   if ( !aNbE )
4987     return EXTR_NO_ELEMENTS;
4988
4989   // 1.1 Track Pattern
4990   ASSERT( theTrack );
4991
4992   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4993
4994   aItE = pMeshDS->elementsIterator();
4995   while ( aItE->more() ) {
4996     const SMDS_MeshElement* pE = aItE->next();
4997     aTypeE = pE->GetType();
4998     // Pattern must contain links only
4999     if ( aTypeE != SMDSAbs_Edge )
5000       return EXTR_PATH_NOT_EDGE;
5001   }
5002
5003   list<SMESH_MeshEditor_PathPoint> fullList;
5004
5005   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
5006
5007   if( aS == SMESH_Mesh::PseudoShape() ) {
5008     //Mesh without shape
5009     const SMDS_MeshNode* currentNode = NULL;
5010     const SMDS_MeshNode* prevNode = theN1;
5011     std::vector<const SMDS_MeshNode*> aNodesList;
5012     aNodesList.push_back(theN1);
5013     int nbEdges = 0, conn=0;
5014     const SMDS_MeshElement* prevElem = NULL;
5015     const SMDS_MeshElement* currentElem = NULL;
5016     int totalNbEdges = theTrack->NbEdges();
5017     SMDS_ElemIteratorPtr nIt;
5018
5019     //check start node
5020     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
5021       return EXTR_BAD_STARTING_NODE;
5022     }
5023
5024     conn = nbEdgeConnectivity(theN1);
5025     if(conn > 2)
5026       return EXTR_PATH_NOT_EDGE;
5027
5028     aItE = theN1->GetInverseElementIterator();
5029     prevElem = aItE->next();
5030     currentElem = prevElem;
5031     //Get all nodes
5032     if(totalNbEdges == 1 ) {
5033       nIt = currentElem->nodesIterator();
5034       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5035       if(currentNode == prevNode)
5036         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5037       aNodesList.push_back(currentNode);
5038     } else {
5039       nIt = currentElem->nodesIterator();
5040       while( nIt->more() ) {
5041         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5042         if(currentNode == prevNode)
5043           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5044         aNodesList.push_back(currentNode);
5045
5046         //case of the closed mesh
5047         if(currentNode == theN1) {
5048           nbEdges++;
5049           break;
5050         }
5051
5052         conn = nbEdgeConnectivity(currentNode);
5053         if(conn > 2) {
5054           return EXTR_PATH_NOT_EDGE;
5055         }else if( conn == 1 && nbEdges > 0 ) {
5056           //End of the path
5057           nbEdges++;
5058           break;
5059         }else {
5060           prevNode = currentNode;
5061           aItE = currentNode->GetInverseElementIterator();
5062           currentElem = aItE->next();
5063           if( currentElem  == prevElem)
5064             currentElem = aItE->next();
5065           nIt = currentElem->nodesIterator();
5066           prevElem = currentElem;
5067           nbEdges++;
5068         }
5069       }
5070     }
5071
5072     if(nbEdges != totalNbEdges)
5073       return EXTR_PATH_NOT_EDGE;
5074
5075     TopTools_SequenceOfShape Edges;
5076     double x1,x2,y1,y2,z1,z2;
5077     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5078     int startNid = theN1->GetID();
5079     for(int i = 1; i < aNodesList.size(); i++) {
5080       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
5081       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
5082       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
5083       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));
5084       list<SMESH_MeshEditor_PathPoint> LPP;
5085       aPrms.clear();
5086       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
5087       LLPPs.push_back(LPP);
5088       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
5089       else startNid = aNodesList[i-1]->GetID();
5090
5091     }
5092
5093     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5094     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5095     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5096     for(; itPP!=firstList.end(); itPP++) {
5097       fullList.push_back( *itPP );
5098     }
5099
5100     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5101     SMESH_MeshEditor_PathPoint PP2;
5102     fullList.pop_back();
5103     itLLPP++;
5104     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5105       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5106       itPP = currList.begin();
5107       PP2 = currList.front();
5108       gp_Dir D1 = PP1.Tangent();
5109       gp_Dir D2 = PP2.Tangent();
5110       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5111                            (D1.Z()+D2.Z())/2 ) );
5112       PP1.SetTangent(Dnew);
5113       fullList.push_back(PP1);
5114       itPP++;
5115       for(; itPP!=currList.end(); itPP++) {
5116         fullList.push_back( *itPP );
5117       }
5118       PP1 = fullList.back();
5119       fullList.pop_back();
5120     }
5121     fullList.push_back(PP1);
5122
5123   } // Sub-shape for the Pattern must be an Edge or Wire
5124   else if( aS.ShapeType() == TopAbs_EDGE ) {
5125     aTrackEdge = TopoDS::Edge( aS );
5126     // the Edge must not be degenerated
5127     if ( BRep_Tool::Degenerated( aTrackEdge ) )
5128       return EXTR_BAD_PATH_SHAPE;
5129     TopExp::Vertices( aTrackEdge, aV1, aV2 );
5130     const SMDS_MeshNode* aN1 = 0;
5131     const SMDS_MeshNode* aN2 = 0;
5132     if ( theTrack->GetSubMesh( aV1 ) && theTrack->GetSubMesh( aV1 )->GetSubMeshDS() ) {
5133       aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
5134       aN1 = aItN->next();
5135     }
5136     if ( theTrack->GetSubMesh( aV2 ) && theTrack->GetSubMesh( aV2 )->GetSubMeshDS() ) {
5137       aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
5138       aN2 = aItN->next();
5139     }
5140     // starting node must be aN1 or aN2
5141     if ( !( aN1 == theN1 || aN2 == theN1 ) )
5142       return EXTR_BAD_STARTING_NODE;
5143     aItN = pMeshDS->nodesIterator();
5144     while ( aItN->more() ) {
5145       const SMDS_MeshNode* pNode = aItN->next();
5146       if( pNode==aN1 || pNode==aN2 ) continue;
5147       const SMDS_EdgePosition* pEPos =
5148         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5149       double aT = pEPos->GetUParameter();
5150       aPrms.push_back( aT );
5151     }
5152     //Extrusion_Error err =
5153     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5154   }
5155   else if( aS.ShapeType() == TopAbs_WIRE ) {
5156     list< SMESH_subMesh* > LSM;
5157     TopTools_SequenceOfShape Edges;
5158     TopExp_Explorer eExp(aS, TopAbs_EDGE);
5159     for(; eExp.More(); eExp.Next()) {
5160       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5161       if( BRep_Tool::Degenerated(E) ) continue;
5162       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5163       if(SM) {
5164         LSM.push_back(SM);
5165         Edges.Append(E);
5166       }
5167     }
5168     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5169     TopoDS_Vertex aVprev;
5170     TColStd_MapOfInteger UsedNums;
5171     int NbEdges = Edges.Length();
5172     int i = 1;
5173     for(; i<=NbEdges; i++) {
5174       int k = 0;
5175       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5176       for(; itLSM!=LSM.end(); itLSM++) {
5177         k++;
5178         if(UsedNums.Contains(k)) continue;
5179         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5180         SMESH_subMesh* locTrack = *itLSM;
5181         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5182         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5183         bool aN1isOK = false, aN2isOK = false;
5184         if ( aVprev.IsNull() ) {
5185           // if previous vertex is not yet defined, it means that we in the beginning of wire
5186           // and we have to find initial vertex corresponding to starting node theN1
5187           const SMDS_MeshNode* aN1 = 0;
5188           const SMDS_MeshNode* aN2 = 0;
5189
5190           if ( locTrack->GetFather()->GetSubMesh(aV1) && locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS() ) {
5191             aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5192             aN1 = aItN->next();
5193           }
5194           if ( locTrack->GetFather()->GetSubMesh(aV2) && locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS() ) {
5195             aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5196             aN2 = aItN->next();
5197           }
5198           // starting node must be aN1 or aN2
5199           aN1isOK = ( aN1 && aN1 == theN1 );
5200           aN2isOK = ( aN2 && aN2 == theN1 );
5201         }
5202         else {
5203           // we have specified ending vertex of the previous edge on the previous iteration
5204           // and we have just to check that it corresponds to any vertex in current segment
5205           aN1isOK = aVprev.IsSame( aV1 );
5206           aN2isOK = aVprev.IsSame( aV2 );
5207         }
5208         if ( !aN1isOK && !aN2isOK ) continue;
5209         // 2. Collect parameters on the track edge
5210         aPrms.clear();
5211         aItN = locMeshDS->GetNodes();
5212         while ( aItN->more() ) {
5213           const SMDS_MeshNode*     pNode = aItN->next();
5214           const SMDS_EdgePosition* pEPos =
5215             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5216           double aT = pEPos->GetUParameter();
5217           aPrms.push_back( aT );
5218         }
5219         list<SMESH_MeshEditor_PathPoint> LPP;
5220         //Extrusion_Error err =
5221         MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
5222         LLPPs.push_back(LPP);
5223         UsedNums.Add(k);
5224         // update startN for search following egde
5225         if ( aN1isOK ) aVprev = aV2;
5226         else           aVprev = aV1;
5227         break;
5228       }
5229     }
5230     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5231     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5232     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5233     for(; itPP!=firstList.end(); itPP++) {
5234       fullList.push_back( *itPP );
5235     }
5236     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5237     fullList.pop_back();
5238     itLLPP++;
5239     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5240       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5241       itPP = currList.begin();
5242       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5243       gp_Dir D1 = PP1.Tangent();
5244       gp_Dir D2 = PP2.Tangent();
5245       gp_Dir Dnew( ( D1.XYZ() + D2.XYZ() ) / 2 );
5246       PP1.SetTangent(Dnew);
5247       fullList.push_back(PP1);
5248       itPP++;
5249       for(; itPP!=currList.end(); itPP++) {
5250         fullList.push_back( *itPP );
5251       }
5252       PP1 = fullList.back();
5253       fullList.pop_back();
5254     }
5255     // if wire not closed
5256     fullList.push_back(PP1);
5257     // else ???
5258   }
5259   else {
5260     return EXTR_BAD_PATH_SHAPE;
5261   }
5262
5263   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5264                           theHasRefPoint, theRefPoint, theMakeGroups);
5265 }
5266
5267
5268 //=======================================================================
5269 //function : MakeEdgePathPoints
5270 //purpose  : auxilary for ExtrusionAlongTrack
5271 //=======================================================================
5272 SMESH_MeshEditor::Extrusion_Error
5273 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5274                                      const TopoDS_Edge& aTrackEdge,
5275                                      bool FirstIsStart,
5276                                      list<SMESH_MeshEditor_PathPoint>& LPP)
5277 {
5278   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5279   aTolVec=1.e-7;
5280   aTolVec2=aTolVec*aTolVec;
5281   double aT1, aT2;
5282   TopoDS_Vertex aV1, aV2;
5283   TopExp::Vertices( aTrackEdge, aV1, aV2 );
5284   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5285   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5286   // 2. Collect parameters on the track edge
5287   aPrms.push_front( aT1 );
5288   aPrms.push_back( aT2 );
5289   // sort parameters
5290   aPrms.sort();
5291   if( FirstIsStart ) {
5292     if ( aT1 > aT2 ) {
5293       aPrms.reverse();
5294     }
5295   }
5296   else {
5297     if ( aT2 > aT1 ) {
5298       aPrms.reverse();
5299     }
5300   }
5301   // 3. Path Points
5302   SMESH_MeshEditor_PathPoint aPP;
5303   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5304   std::list<double>::iterator aItD = aPrms.begin();
5305   for(; aItD != aPrms.end(); ++aItD) {
5306     double aT = *aItD;
5307     gp_Pnt aP3D;
5308     gp_Vec aVec;
5309     aC3D->D1( aT, aP3D, aVec );
5310     aL2 = aVec.SquareMagnitude();
5311     if ( aL2 < aTolVec2 )
5312       return EXTR_CANT_GET_TANGENT;
5313     gp_Dir aTgt( aVec );
5314     aPP.SetPnt( aP3D );
5315     aPP.SetTangent( aTgt );
5316     aPP.SetParameter( aT );
5317     LPP.push_back(aPP);
5318   }
5319   return EXTR_OK;
5320 }
5321
5322
5323 //=======================================================================
5324 //function : MakeExtrElements
5325 //purpose  : auxilary for ExtrusionAlongTrack
5326 //=======================================================================
5327 SMESH_MeshEditor::Extrusion_Error
5328 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5329                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5330                                    const bool theHasAngles,
5331                                    list<double>& theAngles,
5332                                    const bool theLinearVariation,
5333                                    const bool theHasRefPoint,
5334                                    const gp_Pnt& theRefPoint,
5335                                    const bool theMakeGroups)
5336 {
5337   MESSAGE("MakeExtrElements");
5338   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5339   int aNbTP = fullList.size();
5340   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5341   // Angles
5342   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5343     LinearAngleVariation(aNbTP-1, theAngles);
5344   }
5345   vector<double> aAngles( aNbTP );
5346   int j = 0;
5347   for(; j<aNbTP; ++j) {
5348     aAngles[j] = 0.;
5349   }
5350   if ( theHasAngles ) {
5351     double anAngle;;
5352     std::list<double>::iterator aItD = theAngles.begin();
5353     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5354       anAngle = *aItD;
5355       aAngles[j] = anAngle;
5356     }
5357   }
5358   // fill vector of path points with angles
5359   //aPPs.resize(fullList.size());
5360   j = -1;
5361   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5362   for(; itPP!=fullList.end(); itPP++) {
5363     j++;
5364     SMESH_MeshEditor_PathPoint PP = *itPP;
5365     PP.SetAngle(aAngles[j]);
5366     aPPs[j] = PP;
5367   }
5368
5369   TNodeOfNodeListMap mapNewNodes;
5370   TElemOfVecOfNnlmiMap mapElemNewNodes;
5371   TElemOfElemListMap newElemsMap;
5372   TIDSortedElemSet::iterator itElem;
5373   double aX, aY, aZ;
5374   int aNb;
5375   SMDSAbs_ElementType aTypeE;
5376   // source elements for each generated one
5377   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5378
5379   // 3. Center of rotation aV0
5380   gp_Pnt aV0 = theRefPoint;
5381   gp_XYZ aGC;
5382   if ( !theHasRefPoint ) {
5383     aNb = 0;
5384     aGC.SetCoord( 0.,0.,0. );
5385
5386     itElem = theElements.begin();
5387     for ( ; itElem != theElements.end(); itElem++ ) {
5388       const SMDS_MeshElement* elem = *itElem;
5389
5390       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5391       while ( itN->more() ) {
5392         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5393         aX = node->X();
5394         aY = node->Y();
5395         aZ = node->Z();
5396
5397         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5398           list<const SMDS_MeshNode*> aLNx;
5399           mapNewNodes[node] = aLNx;
5400           //
5401           gp_XYZ aXYZ( aX, aY, aZ );
5402           aGC += aXYZ;
5403           ++aNb;
5404         }
5405       }
5406     }
5407     aGC /= aNb;
5408     aV0.SetXYZ( aGC );
5409   } // if (!theHasRefPoint) {
5410   mapNewNodes.clear();
5411
5412   // 4. Processing the elements
5413   SMESHDS_Mesh* aMesh = GetMeshDS();
5414
5415   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5416     // check element type
5417     const SMDS_MeshElement* elem = *itElem;
5418     aTypeE = elem->GetType();
5419     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5420       continue;
5421
5422     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5423     newNodesItVec.reserve( elem->NbNodes() );
5424
5425     // loop on elem nodes
5426     int nodeIndex = -1;
5427     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5428     while ( itN->more() )
5429     {
5430       ++nodeIndex;
5431       // check if a node has been already processed
5432       const SMDS_MeshNode* node =
5433         static_cast<const SMDS_MeshNode*>( itN->next() );
5434       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5435       if ( nIt == mapNewNodes.end() ) {
5436         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5437         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5438
5439         // make new nodes
5440         aX = node->X();  aY = node->Y(); aZ = node->Z();
5441
5442         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5443         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5444         gp_Ax1 anAx1, anAxT1T0;
5445         gp_Dir aDT1x, aDT0x, aDT1T0;
5446
5447         aTolAng=1.e-4;
5448
5449         aV0x = aV0;
5450         aPN0.SetCoord(aX, aY, aZ);
5451
5452         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5453         aP0x = aPP0.Pnt();
5454         aDT0x= aPP0.Tangent();
5455         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5456
5457         for ( j = 1; j < aNbTP; ++j ) {
5458           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5459           aP1x = aPP1.Pnt();
5460           aDT1x = aPP1.Tangent();
5461           aAngle1x = aPP1.Angle();
5462
5463           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5464           // Translation
5465           gp_Vec aV01x( aP0x, aP1x );
5466           aTrsf.SetTranslation( aV01x );
5467
5468           // traslated point
5469           aV1x = aV0x.Transformed( aTrsf );
5470           aPN1 = aPN0.Transformed( aTrsf );
5471
5472           // rotation 1 [ T1,T0 ]
5473           aAngleT1T0=-aDT1x.Angle( aDT0x );
5474           if (fabs(aAngleT1T0) > aTolAng) {
5475             aDT1T0=aDT1x^aDT0x;
5476             anAxT1T0.SetLocation( aV1x );
5477             anAxT1T0.SetDirection( aDT1T0 );
5478             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5479
5480             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5481           }
5482
5483           // rotation 2
5484           if ( theHasAngles ) {
5485             anAx1.SetLocation( aV1x );
5486             anAx1.SetDirection( aDT1x );
5487             aTrsfRot.SetRotation( anAx1, aAngle1x );
5488
5489             aPN1 = aPN1.Transformed( aTrsfRot );
5490           }
5491
5492           // make new node
5493           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5494           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5495             // create additional node
5496             double x = ( aPN1.X() + aPN0.X() )/2.;
5497             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5498             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5499             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5500             myLastCreatedNodes.Append(newNode);
5501             srcNodes.Append( node );
5502             listNewNodes.push_back( newNode );
5503           }
5504           aX = aPN1.X();
5505           aY = aPN1.Y();
5506           aZ = aPN1.Z();
5507           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5508           myLastCreatedNodes.Append(newNode);
5509           srcNodes.Append( node );
5510           listNewNodes.push_back( newNode );
5511
5512           aPN0 = aPN1;
5513           aP0x = aP1x;
5514           aV0x = aV1x;
5515           aDT0x = aDT1x;
5516         }
5517       }
5518
5519       else {
5520         // if current elem is quadratic and current node is not medium
5521         // we have to check - may be it is needed to insert additional nodes
5522         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5523           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5524           if(listNewNodes.size()==aNbTP-1) {
5525             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5526             gp_XYZ P(node->X(), node->Y(), node->Z());
5527             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5528             int i;
5529             for(i=0; i<aNbTP-1; i++) {
5530               const SMDS_MeshNode* N = *it;
5531               double x = ( N->X() + P.X() )/2.;
5532               double y = ( N->Y() + P.Y() )/2.;
5533               double z = ( N->Z() + P.Z() )/2.;
5534               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5535               srcNodes.Append( node );
5536               myLastCreatedNodes.Append(newN);
5537               aNodes[2*i] = newN;
5538               aNodes[2*i+1] = N;
5539               P = gp_XYZ(N->X(),N->Y(),N->Z());
5540             }
5541             listNewNodes.clear();
5542             for(i=0; i<2*(aNbTP-1); i++) {
5543               listNewNodes.push_back(aNodes[i]);
5544             }
5545           }
5546         }
5547       }
5548
5549       newNodesItVec.push_back( nIt );
5550     }
5551     // make new elements
5552     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5553     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5554     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5555   }
5556
5557   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5558
5559   if ( theMakeGroups )
5560     generateGroups( srcNodes, srcElems, "extruded");
5561
5562   return EXTR_OK;
5563 }
5564
5565
5566 //=======================================================================
5567 //function : LinearAngleVariation
5568 //purpose  : auxilary for ExtrusionAlongTrack
5569 //=======================================================================
5570 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5571                                             list<double>& Angles)
5572 {
5573   int nbAngles = Angles.size();
5574   if( nbSteps > nbAngles ) {
5575     vector<double> theAngles(nbAngles);
5576     list<double>::iterator it = Angles.begin();
5577     int i = -1;
5578     for(; it!=Angles.end(); it++) {
5579       i++;
5580       theAngles[i] = (*it);
5581     }
5582     list<double> res;
5583     double rAn2St = double( nbAngles ) / double( nbSteps );
5584     double angPrev = 0, angle;
5585     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5586       double angCur = rAn2St * ( iSt+1 );
5587       double angCurFloor  = floor( angCur );
5588       double angPrevFloor = floor( angPrev );
5589       if ( angPrevFloor == angCurFloor )
5590         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5591       else {
5592         int iP = int( angPrevFloor );
5593         double angPrevCeil = ceil(angPrev);
5594         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5595
5596         int iC = int( angCurFloor );
5597         if ( iC < nbAngles )
5598           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5599
5600         iP = int( angPrevCeil );
5601         while ( iC-- > iP )
5602           angle += theAngles[ iC ];
5603       }
5604       res.push_back(angle);
5605       angPrev = angCur;
5606     }
5607     Angles.clear();
5608     it = res.begin();
5609     for(; it!=res.end(); it++)
5610       Angles.push_back( *it );
5611   }
5612 }
5613
5614
5615 //================================================================================
5616 /*!
5617  * \brief Move or copy theElements applying theTrsf to their nodes
5618  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5619  *  \param theTrsf - transformation to apply
5620  *  \param theCopy - if true, create translated copies of theElems
5621  *  \param theMakeGroups - if true and theCopy, create translated groups
5622  *  \param theTargetMesh - mesh to copy translated elements into
5623  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5624  */
5625 //================================================================================
5626
5627 SMESH_MeshEditor::PGroupIDs
5628 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5629                              const gp_Trsf&     theTrsf,
5630                              const bool         theCopy,
5631                              const bool         theMakeGroups,
5632                              SMESH_Mesh*        theTargetMesh)
5633 {
5634   myLastCreatedElems.Clear();
5635   myLastCreatedNodes.Clear();
5636
5637   bool needReverse = false;
5638   string groupPostfix;
5639   switch ( theTrsf.Form() ) {
5640   case gp_PntMirror:
5641     MESSAGE("gp_PntMirror");
5642     needReverse = true;
5643     groupPostfix = "mirrored";
5644     break;
5645   case gp_Ax1Mirror:
5646     MESSAGE("gp_Ax1Mirror");
5647     groupPostfix = "mirrored";
5648     break;
5649   case gp_Ax2Mirror:
5650     MESSAGE("gp_Ax2Mirror");
5651     needReverse = true;
5652     groupPostfix = "mirrored";
5653     break;
5654   case gp_Rotation:
5655     MESSAGE("gp_Rotation");
5656     groupPostfix = "rotated";
5657     break;
5658   case gp_Translation:
5659     MESSAGE("gp_Translation");
5660     groupPostfix = "translated";
5661     break;
5662   case gp_Scale:
5663     MESSAGE("gp_Scale");
5664     groupPostfix = "scaled";
5665     break;
5666   case gp_CompoundTrsf: // different scale by axis
5667     MESSAGE("gp_CompoundTrsf");
5668     groupPostfix = "scaled";
5669     break;
5670   default:
5671     MESSAGE("default");
5672     needReverse = false;
5673     groupPostfix = "transformed";
5674   }
5675
5676   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5677   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5678   SMESHDS_Mesh* aMesh    = GetMeshDS();
5679
5680
5681   // map old node to new one
5682   TNodeNodeMap nodeMap;
5683
5684   // elements sharing moved nodes; those of them which have all
5685   // nodes mirrored but are not in theElems are to be reversed
5686   TIDSortedElemSet inverseElemSet;
5687
5688   // source elements for each generated one
5689   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5690
5691   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5692   TIDSortedElemSet orphanNode;
5693
5694   if ( theElems.empty() ) // transform the whole mesh
5695   {
5696     // add all elements
5697     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5698     while ( eIt->more() ) theElems.insert( eIt->next() );
5699     // add orphan nodes
5700     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5701     while ( nIt->more() )
5702     {
5703       const SMDS_MeshNode* node = nIt->next();
5704       if ( node->NbInverseElements() == 0)
5705         orphanNode.insert( node );
5706     }
5707   }
5708
5709   // loop on elements to transform nodes : first orphan nodes then elems
5710   TIDSortedElemSet::iterator itElem;
5711   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5712   for (int i=0; i<2; i++)
5713   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5714     const SMDS_MeshElement* elem = *itElem;
5715     if ( !elem )
5716       continue;
5717
5718     // loop on elem nodes
5719     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5720     while ( itN->more() ) {
5721
5722       const SMDS_MeshNode* node = cast2Node( itN->next() );
5723       // check if a node has been already transformed
5724       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5725         nodeMap.insert( make_pair ( node, node ));
5726       if ( !n2n_isnew.second )
5727         continue;
5728
5729       double coord[3];
5730       coord[0] = node->X();
5731       coord[1] = node->Y();
5732       coord[2] = node->Z();
5733       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5734       if ( theTargetMesh ) {
5735         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5736         n2n_isnew.first->second = newNode;
5737         myLastCreatedNodes.Append(newNode);
5738         srcNodes.Append( node );
5739       }
5740       else if ( theCopy ) {
5741         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5742         n2n_isnew.first->second = newNode;
5743         myLastCreatedNodes.Append(newNode);
5744         srcNodes.Append( node );
5745       }
5746       else {
5747         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5748         // node position on shape becomes invalid
5749         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5750           ( SMDS_SpacePosition::originSpacePosition() );
5751       }
5752
5753       // keep inverse elements
5754       if ( !theCopy && !theTargetMesh && needReverse ) {
5755         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5756         while ( invElemIt->more() ) {
5757           const SMDS_MeshElement* iel = invElemIt->next();
5758           inverseElemSet.insert( iel );
5759         }
5760       }
5761     }
5762   }
5763
5764   // either create new elements or reverse mirrored ones
5765   if ( !theCopy && !needReverse && !theTargetMesh )
5766     return PGroupIDs();
5767
5768   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5769   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5770     theElems.insert( *invElemIt );
5771
5772   // Replicate or reverse elements
5773
5774   std::vector<int> iForw;
5775   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5776   {
5777     const SMDS_MeshElement* elem = *itElem;
5778     if ( !elem ) continue;
5779
5780     SMDSAbs_GeometryType geomType = elem->GetGeomType();
5781     int                  nbNodes  = elem->NbNodes();
5782     if ( geomType == SMDSGeom_NONE ) continue; // node
5783
5784     switch ( geomType ) {
5785
5786     case SMDSGeom_POLYGON:  // ---------------------- polygon
5787       {
5788         vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5789         int iNode = 0;
5790         SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5791         while (itN->more()) {
5792           const SMDS_MeshNode* node =
5793             static_cast<const SMDS_MeshNode*>(itN->next());
5794           TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5795           if (nodeMapIt == nodeMap.end())
5796             break; // not all nodes transformed
5797           if (needReverse) {
5798             // reverse mirrored faces and volumes
5799             poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5800           } else {
5801             poly_nodes[iNode] = (*nodeMapIt).second;
5802           }
5803           iNode++;
5804         }
5805         if ( iNode != nbNodes )
5806           continue; // not all nodes transformed
5807
5808         if ( theTargetMesh ) {
5809           myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5810           srcElems.Append( elem );
5811         }
5812         else if ( theCopy ) {
5813           myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5814           srcElems.Append( elem );
5815         }
5816         else {
5817           aMesh->ChangePolygonNodes(elem, poly_nodes);
5818         }
5819       }
5820       break;
5821
5822     case SMDSGeom_POLYHEDRA:  // ------------------ polyhedral volume
5823       {
5824         const SMDS_VtkVolume* aPolyedre =
5825           dynamic_cast<const SMDS_VtkVolume*>( elem );
5826         if (!aPolyedre) {
5827           MESSAGE("Warning: bad volumic element");
5828           continue;
5829         }
5830
5831         vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
5832         vector<int> quantities; quantities.reserve( nbNodes );
5833
5834         bool allTransformed = true;
5835         int nbFaces = aPolyedre->NbFaces();
5836         for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5837           int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5838           for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5839             const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5840             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5841             if (nodeMapIt == nodeMap.end()) {
5842               allTransformed = false; // not all nodes transformed
5843             } else {
5844               poly_nodes.push_back((*nodeMapIt).second);
5845             }
5846             if ( needReverse && allTransformed )
5847               std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
5848           }
5849           quantities.push_back(nbFaceNodes);
5850         }
5851         if ( !allTransformed )
5852           continue; // not all nodes transformed
5853
5854         if ( theTargetMesh ) {
5855           myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5856           srcElems.Append( elem );
5857         }
5858         else if ( theCopy ) {
5859           myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5860           srcElems.Append( elem );
5861         }
5862         else {
5863           aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5864         }
5865       }
5866       break;
5867
5868     case SMDSGeom_BALL: // -------------------- Ball
5869       {
5870         if ( !theCopy && !theTargetMesh ) continue;
5871
5872         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) );
5873         if (nodeMapIt == nodeMap.end())
5874           continue; // not all nodes transformed
5875
5876         double diameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
5877         if ( theTargetMesh ) {
5878           myLastCreatedElems.Append(aTgtMesh->AddBall( nodeMapIt->second, diameter ));
5879           srcElems.Append( elem );
5880         }
5881         else {
5882           myLastCreatedElems.Append(aMesh->AddBall( nodeMapIt->second, diameter ));
5883           srcElems.Append( elem );
5884         }
5885       }
5886       break;
5887
5888     default: // ----------------------- Regular elements
5889
5890       while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
5891       const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
5892       const std::vector<int>& i = needReverse ? iRev : iForw;
5893
5894       // find transformed nodes
5895       vector<const SMDS_MeshNode*> nodes(nbNodes);
5896       int iNode = 0;
5897       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5898       while ( itN->more() ) {
5899         const SMDS_MeshNode* node =
5900           static_cast<const SMDS_MeshNode*>( itN->next() );
5901         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5902         if ( nodeMapIt == nodeMap.end() )
5903           break; // not all nodes transformed
5904         nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5905       }
5906       if ( iNode != nbNodes )
5907         continue; // not all nodes transformed
5908
5909       if ( theTargetMesh ) {
5910         if ( SMDS_MeshElement* copy =
5911              targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5912           myLastCreatedElems.Append( copy );
5913           srcElems.Append( elem );
5914         }
5915       }
5916       else if ( theCopy ) {
5917         if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5918           srcElems.Append( elem );
5919       }
5920       else {
5921         // reverse element as it was reversed by transformation
5922         if ( nbNodes > 2 )
5923           aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5924       }
5925     } // switch ( geomType )
5926
5927   } // loop on elements
5928
5929   PGroupIDs newGroupIDs;
5930
5931   if ( ( theMakeGroups && theCopy ) ||
5932        ( theMakeGroups && theTargetMesh ) )
5933     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5934
5935   return newGroupIDs;
5936 }
5937
5938 //=======================================================================
5939 /*!
5940  * \brief Create groups of elements made during transformation
5941  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5942  * \param elemGens - elements making corresponding myLastCreatedElems
5943  * \param postfix - to append to names of new groups
5944  */
5945 //=======================================================================
5946
5947 SMESH_MeshEditor::PGroupIDs
5948 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5949                                  const SMESH_SequenceOfElemPtr& elemGens,
5950                                  const std::string&             postfix,
5951                                  SMESH_Mesh*                    targetMesh)
5952 {
5953   PGroupIDs newGroupIDs( new list<int> );
5954   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5955
5956   // Sort existing groups by types and collect their names
5957
5958   // to store an old group and a generated new ones
5959   using boost::tuple;
5960   using boost::make_tuple;
5961   typedef tuple< SMESHDS_GroupBase*, SMESHDS_Group*, SMESHDS_Group* > TOldNewGroup;
5962   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5963   vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups
5964   // group names
5965   set< string > groupNames;
5966
5967   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5968   if ( !groupIt->more() ) return newGroupIDs;
5969
5970   int newGroupID = mesh->GetGroupIds().back()+1;
5971   while ( groupIt->more() )
5972   {
5973     SMESH_Group * group = groupIt->next();
5974     if ( !group ) continue;
5975     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5976     if ( !groupDS || groupDS->IsEmpty() ) continue;
5977     groupNames.insert    ( group->GetName() );
5978     groupDS->SetStoreName( group->GetName() );
5979     const SMDSAbs_ElementType type = groupDS->GetType();
5980     SMESHDS_Group* newGroup    = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
5981     SMESHDS_Group* newTopGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
5982     groupsByType[ type ].push_back( make_tuple( groupDS, newGroup, newTopGroup ));
5983     orderedOldNewGroups.push_back( & groupsByType[ type ].back() );
5984   }
5985
5986   // Loop on nodes and elements to add them in new groups
5987
5988   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5989   {
5990     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5991     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5992     if ( gens.Length() != elems.Length() )
5993       throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args");
5994
5995     // loop on created elements
5996     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5997     {
5998       const SMDS_MeshElement* sourceElem = gens( iElem );
5999       if ( !sourceElem ) {
6000         MESSAGE("generateGroups(): NULL source element");
6001         continue;
6002       }
6003       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6004       if ( groupsOldNew.empty() ) { // no groups of this type at all
6005         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6006           ++iElem; // skip all elements made by sourceElem
6007         continue;
6008       }
6009       // collect all elements made by the iElem-th sourceElem
6010       list< const SMDS_MeshElement* > resultElems;
6011       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6012         if ( resElem != sourceElem )
6013           resultElems.push_back( resElem );
6014       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6015         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6016           if ( resElem != sourceElem )
6017             resultElems.push_back( resElem );
6018
6019       // there must be a top element
6020       const SMDS_MeshElement* topElem = 0;
6021       if ( isNodes )
6022       {
6023         topElem = resultElems.back();
6024         resultElems.pop_back();
6025       }
6026       else
6027       {
6028         list< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin();
6029         for ( ; resElemIt != resultElems.rend() ; ++resElemIt )
6030           if ( (*resElemIt)->GetType() == sourceElem->GetType() )
6031           {
6032             topElem = *resElemIt;
6033             resultElems.erase( --(resElemIt.base()) ); // erase *resElemIt
6034             break;
6035           }
6036       }
6037
6038       // add resultElems to groups originted from ones the sourceElem belongs to
6039       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6040       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6041       {
6042         SMESHDS_GroupBase* oldGroup = gOldNew->get<0>();
6043         if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup
6044         {
6045           // fill in a new group
6046           SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup();
6047           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6048           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6049             newGroup.Add( *resElemIt );
6050
6051           // fill a "top" group
6052           if ( topElem )
6053           {
6054             SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup();
6055             newTopGroup.Add( topElem );
6056           }
6057         }
6058       }
6059     } // loop on created elements
6060   }// loop on nodes and elements
6061
6062   // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups
6063
6064   list<int> topGrouIds;
6065   for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i )
6066   {
6067     SMESHDS_GroupBase* oldGroupDS =   orderedOldNewGroups[i]->get<0>();
6068     SMESHDS_Group*   newGroups[2] = { orderedOldNewGroups[i]->get<1>(),
6069                                       orderedOldNewGroups[i]->get<2>() };
6070     const int nbNewGroups = !newGroups[0]->IsEmpty() + !newGroups[1]->IsEmpty();
6071     for ( int is2nd = 0; is2nd < 2; ++is2nd )
6072     {
6073       SMESHDS_Group* newGroupDS = newGroups[ is2nd ];
6074       if ( newGroupDS->IsEmpty() )
6075       {
6076         mesh->GetMeshDS()->RemoveGroup( newGroupDS );
6077       }
6078       else
6079       {
6080         // set group type
6081         newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
6082
6083         // make a name
6084         const bool isTop = ( nbNewGroups == 2 &&
6085                              newGroupDS->GetType() == oldGroupDS->GetType() &&
6086                              is2nd );
6087
6088         string name = oldGroupDS->GetStoreName();
6089         if ( !targetMesh ) {
6090           string suffix = ( isTop ? "top": postfix.c_str() );
6091           name += "_";
6092           name += suffix;
6093           int nb = 1;
6094           while ( !groupNames.insert( name ).second ) // name exists
6095             name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << suffix << "_" << nb++;
6096         }
6097         else if ( isTop ) {
6098           name += "_top";
6099         }
6100         newGroupDS->SetStoreName( name.c_str() );
6101
6102         // make a SMESH_Groups
6103         mesh->AddGroup( newGroupDS );
6104         if ( isTop )
6105           topGrouIds.push_back( newGroupDS->GetID() );
6106         else
6107           newGroupIDs->push_back( newGroupDS->GetID() );
6108       }
6109     }
6110   }
6111   newGroupIDs->splice( newGroupIDs->end(), topGrouIds );
6112
6113   return newGroupIDs;
6114 }
6115
6116 //================================================================================
6117 /*!
6118  * \brief Return list of group of nodes close to each other within theTolerance
6119  *        Search among theNodes or in the whole mesh if theNodes is empty using
6120  *        an Octree algorithm
6121  */
6122 //================================================================================
6123
6124 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6125                                             const double         theTolerance,
6126                                             TListOfListOfNodes & theGroupsOfNodes)
6127 {
6128   myLastCreatedElems.Clear();
6129   myLastCreatedNodes.Clear();
6130
6131   if ( theNodes.empty() )
6132   { // get all nodes in the mesh
6133     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6134     while ( nIt->more() )
6135       theNodes.insert( theNodes.end(),nIt->next());
6136   }
6137
6138   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6139 }
6140
6141 //=======================================================================
6142 //function : SimplifyFace
6143 //purpose  :
6144 //=======================================================================
6145
6146 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *>& faceNodes,
6147                                     vector<const SMDS_MeshNode *>&       poly_nodes,
6148                                     vector<int>&                         quantities) const
6149 {
6150   int nbNodes = faceNodes.size();
6151
6152   if (nbNodes < 3)
6153     return 0;
6154
6155   set<const SMDS_MeshNode*> nodeSet;
6156
6157   // get simple seq of nodes
6158   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6159   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6160   int iSimple = 0, nbUnique = 0;
6161
6162   simpleNodes[iSimple++] = faceNodes[0];
6163   nbUnique++;
6164   for (int iCur = 1; iCur < nbNodes; iCur++) {
6165     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6166       simpleNodes[iSimple++] = faceNodes[iCur];
6167       if (nodeSet.insert( faceNodes[iCur] ).second)
6168         nbUnique++;
6169     }
6170   }
6171   int nbSimple = iSimple;
6172   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6173     nbSimple--;
6174     iSimple--;
6175   }
6176
6177   if (nbUnique < 3)
6178     return 0;
6179
6180   // separate loops
6181   int nbNew = 0;
6182   bool foundLoop = (nbSimple > nbUnique);
6183   while (foundLoop) {
6184     foundLoop = false;
6185     set<const SMDS_MeshNode*> loopSet;
6186     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6187       const SMDS_MeshNode* n = simpleNodes[iSimple];
6188       if (!loopSet.insert( n ).second) {
6189         foundLoop = true;
6190
6191         // separate loop
6192         int iC = 0, curLast = iSimple;
6193         for (; iC < curLast; iC++) {
6194           if (simpleNodes[iC] == n) break;
6195         }
6196         int loopLen = curLast - iC;
6197         if (loopLen > 2) {
6198           // create sub-element
6199           nbNew++;
6200           quantities.push_back(loopLen);
6201           for (; iC < curLast; iC++) {
6202             poly_nodes.push_back(simpleNodes[iC]);
6203           }
6204         }
6205         // shift the rest nodes (place from the first loop position)
6206         for (iC = curLast + 1; iC < nbSimple; iC++) {
6207           simpleNodes[iC - loopLen] = simpleNodes[iC];
6208         }
6209         nbSimple -= loopLen;
6210         iSimple -= loopLen;
6211       }
6212     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6213   } // while (foundLoop)
6214
6215   if (iSimple > 2) {
6216     nbNew++;
6217     quantities.push_back(iSimple);
6218     for (int i = 0; i < iSimple; i++)
6219       poly_nodes.push_back(simpleNodes[i]);
6220   }
6221
6222   return nbNew;
6223 }
6224
6225 //=======================================================================
6226 //function : MergeNodes
6227 //purpose  : In each group, the cdr of nodes are substituted by the first one
6228 //           in all elements.
6229 //=======================================================================
6230
6231 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6232 {
6233   MESSAGE("MergeNodes");
6234   myLastCreatedElems.Clear();
6235   myLastCreatedNodes.Clear();
6236
6237   SMESHDS_Mesh* aMesh = GetMeshDS();
6238
6239   TNodeNodeMap nodeNodeMap; // node to replace - new node
6240   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6241   list< int > rmElemIds, rmNodeIds;
6242
6243   // Fill nodeNodeMap and elems
6244
6245   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6246   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6247     list<const SMDS_MeshNode*>& nodes = *grIt;
6248     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6249     const SMDS_MeshNode* nToKeep = *nIt;
6250     //MESSAGE("node to keep " << nToKeep->GetID());
6251     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6252       const SMDS_MeshNode* nToRemove = *nIt;
6253       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6254       if ( nToRemove != nToKeep ) {
6255         //MESSAGE("  node to remove " << nToRemove->GetID());
6256         rmNodeIds.push_back( nToRemove->GetID() );
6257         AddToSameGroups( nToKeep, nToRemove, aMesh );
6258         // set _alwaysComputed to a sub-mesh of VERTEX to enable mesh computing
6259         // after MergeNodes() w/o creating node in place of merged ones.
6260         const SMDS_PositionPtr& pos = nToRemove->GetPosition();
6261         if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX )
6262           if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() ))
6263             sm->SetIsAlwaysComputed( true );
6264       }
6265
6266       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6267       while ( invElemIt->more() ) {
6268         const SMDS_MeshElement* elem = invElemIt->next();
6269         elems.insert(elem);
6270       }
6271     }
6272   }
6273   // Change element nodes or remove an element
6274
6275   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6276   for ( ; eIt != elems.end(); eIt++ ) {
6277     const SMDS_MeshElement* elem = *eIt;
6278     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
6279     int nbNodes = elem->NbNodes();
6280     int aShapeId = FindShape( elem );
6281
6282     set<const SMDS_MeshNode*> nodeSet;
6283     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6284     int iUnique = 0, iCur = 0, nbRepl = 0;
6285     vector<int> iRepl( nbNodes );
6286
6287     // get new seq of nodes
6288     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6289     while ( itN->more() ) {
6290       const SMDS_MeshNode* n =
6291         static_cast<const SMDS_MeshNode*>( itN->next() );
6292
6293       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6294       if ( nnIt != nodeNodeMap.end() ) { // n sticks
6295         n = (*nnIt).second;
6296         // BUG 0020185: begin
6297         {
6298           bool stopRecur = false;
6299           set<const SMDS_MeshNode*> nodesRecur;
6300           nodesRecur.insert(n);
6301           while (!stopRecur) {
6302             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6303             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6304               n = (*nnIt_i).second;
6305               if (!nodesRecur.insert(n).second) {
6306                 // error: recursive dependancy
6307                 stopRecur = true;
6308               }
6309             }
6310             else
6311               stopRecur = true;
6312           }
6313         }
6314         // BUG 0020185: end
6315       }
6316       curNodes[ iCur ] = n;
6317       bool isUnique = nodeSet.insert( n ).second;
6318       if ( isUnique )
6319         uniqueNodes[ iUnique++ ] = n;
6320       else
6321         iRepl[ nbRepl++ ] = iCur;
6322       iCur++;
6323     }
6324
6325     // Analyse element topology after replacement
6326
6327     bool isOk = true;
6328     int nbUniqueNodes = nodeSet.size();
6329     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
6330     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6331       // Polygons and Polyhedral volumes
6332       if (elem->IsPoly()) {
6333
6334         if (elem->GetType() == SMDSAbs_Face) {
6335           // Polygon
6336           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6337           int inode = 0;
6338           for (; inode < nbNodes; inode++) {
6339             face_nodes[inode] = curNodes[inode];
6340           }
6341
6342           vector<const SMDS_MeshNode *> polygons_nodes;
6343           vector<int> quantities;
6344           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6345           if (nbNew > 0) {
6346             inode = 0;
6347             for (int iface = 0; iface < nbNew; iface++) {
6348               int nbNodes = quantities[iface];
6349               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6350               for (int ii = 0; ii < nbNodes; ii++, inode++) {
6351                 poly_nodes[ii] = polygons_nodes[inode];
6352               }
6353               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6354               myLastCreatedElems.Append(newElem);
6355               if (aShapeId)
6356                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6357             }
6358
6359             MESSAGE("ChangeElementNodes MergeNodes Polygon");
6360             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6361             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
6362             int quid =0;
6363             if (nbNew > 0) quid = nbNew - 1;
6364             vector<int> newquant(quantities.begin()+quid, quantities.end());
6365             const SMDS_MeshElement* newElem = 0;
6366             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
6367             myLastCreatedElems.Append(newElem);
6368             if ( aShapeId && newElem )
6369               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6370             rmElemIds.push_back(elem->GetID());
6371           }
6372           else {
6373             rmElemIds.push_back(elem->GetID());
6374           }
6375
6376         }
6377         else if (elem->GetType() == SMDSAbs_Volume) {
6378           // Polyhedral volume
6379           if (nbUniqueNodes < 4) {
6380             rmElemIds.push_back(elem->GetID());
6381           }
6382           else {
6383             // each face has to be analyzed in order to check volume validity
6384             const SMDS_VtkVolume* aPolyedre =
6385               dynamic_cast<const SMDS_VtkVolume*>( elem );
6386             if (aPolyedre) {
6387               int nbFaces = aPolyedre->NbFaces();
6388
6389               vector<const SMDS_MeshNode *> poly_nodes;
6390               vector<int> quantities;
6391
6392               for (int iface = 1; iface <= nbFaces; iface++) {
6393                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6394                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
6395
6396                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
6397                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
6398                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
6399                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
6400                     faceNode = (*nnIt).second;
6401                   }
6402                   faceNodes[inode - 1] = faceNode;
6403                 }
6404
6405                 SimplifyFace(faceNodes, poly_nodes, quantities);
6406               }
6407
6408               if (quantities.size() > 3) {
6409                 // to be done: remove coincident faces
6410               }
6411
6412               if (quantities.size() > 3)
6413                 {
6414                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
6415                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6416                   const SMDS_MeshElement* newElem = 0;
6417                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
6418                   myLastCreatedElems.Append(newElem);
6419                   if ( aShapeId && newElem )
6420                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
6421                   rmElemIds.push_back(elem->GetID());
6422                 }
6423             }
6424             else {
6425               rmElemIds.push_back(elem->GetID());
6426             }
6427           }
6428         }
6429         else {
6430         }
6431
6432         continue;
6433       } // poly element
6434
6435       // Regular elements
6436       // TODO not all the possible cases are solved. Find something more generic?
6437       switch ( nbNodes ) {
6438       case 2: ///////////////////////////////////// EDGE
6439         isOk = false; break;
6440       case 3: ///////////////////////////////////// TRIANGLE
6441         isOk = false; break;
6442       case 4:
6443         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
6444           isOk = false;
6445         else { //////////////////////////////////// QUADRANGLE
6446           if ( nbUniqueNodes < 3 )
6447             isOk = false;
6448           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
6449             isOk = false; // opposite nodes stick
6450           //MESSAGE("isOk " << isOk);
6451         }
6452         break;
6453       case 6: ///////////////////////////////////// PENTAHEDRON
6454         if ( nbUniqueNodes == 4 ) {
6455           // ---------------------------------> tetrahedron
6456           if (nbRepl == 3 &&
6457               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
6458             // all top nodes stick: reverse a bottom
6459             uniqueNodes[ 0 ] = curNodes [ 1 ];
6460             uniqueNodes[ 1 ] = curNodes [ 0 ];
6461           }
6462           else if (nbRepl == 3 &&
6463                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
6464             // all bottom nodes stick: set a top before
6465             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
6466             uniqueNodes[ 0 ] = curNodes [ 3 ];
6467             uniqueNodes[ 1 ] = curNodes [ 4 ];
6468             uniqueNodes[ 2 ] = curNodes [ 5 ];
6469           }
6470           else if (nbRepl == 4 &&
6471                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
6472             // a lateral face turns into a line: reverse a bottom
6473             uniqueNodes[ 0 ] = curNodes [ 1 ];
6474             uniqueNodes[ 1 ] = curNodes [ 0 ];
6475           }
6476           else
6477             isOk = false;
6478         }
6479         else if ( nbUniqueNodes == 5 ) {
6480           // PENTAHEDRON --------------------> 2 tetrahedrons
6481           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6482             // a bottom node sticks with a linked top one
6483             // 1.
6484             SMDS_MeshElement* newElem =
6485               aMesh->AddVolume(curNodes[ 3 ],
6486                                curNodes[ 4 ],
6487                                curNodes[ 5 ],
6488                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6489             myLastCreatedElems.Append(newElem);
6490             if ( aShapeId )
6491               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6492             // 2. : reverse a bottom
6493             uniqueNodes[ 0 ] = curNodes [ 1 ];
6494             uniqueNodes[ 1 ] = curNodes [ 0 ];
6495             nbUniqueNodes = 4;
6496           }
6497           else
6498             isOk = false;
6499         }
6500         else
6501           isOk = false;
6502         break;
6503       case 8: {
6504         if(elem->IsQuadratic()) { // Quadratic quadrangle
6505           //   1    5    2
6506           //    +---+---+
6507           //    |       |
6508           //    |       |
6509           //   4+       +6
6510           //    |       |
6511           //    |       |
6512           //    +---+---+
6513           //   0    7    3
6514           isOk = false;
6515           if(nbRepl==2) {
6516             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
6517           }
6518           if(nbRepl==3) {
6519             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
6520             nbUniqueNodes = 6;
6521             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6522               uniqueNodes[0] = curNodes[0];
6523               uniqueNodes[1] = curNodes[2];
6524               uniqueNodes[2] = curNodes[3];
6525               uniqueNodes[3] = curNodes[5];
6526               uniqueNodes[4] = curNodes[6];
6527               uniqueNodes[5] = curNodes[7];
6528               isOk = true;
6529             }
6530             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6531               uniqueNodes[0] = curNodes[0];
6532               uniqueNodes[1] = curNodes[1];
6533               uniqueNodes[2] = curNodes[2];
6534               uniqueNodes[3] = curNodes[4];
6535               uniqueNodes[4] = curNodes[5];
6536               uniqueNodes[5] = curNodes[6];
6537               isOk = true;
6538             }
6539             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6540               uniqueNodes[0] = curNodes[1];
6541               uniqueNodes[1] = curNodes[2];
6542               uniqueNodes[2] = curNodes[3];
6543               uniqueNodes[3] = curNodes[5];
6544               uniqueNodes[4] = curNodes[6];
6545               uniqueNodes[5] = curNodes[0];
6546               isOk = true;
6547             }
6548             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
6549               uniqueNodes[0] = curNodes[0];
6550               uniqueNodes[1] = curNodes[1];
6551               uniqueNodes[2] = curNodes[3];
6552               uniqueNodes[3] = curNodes[4];
6553               uniqueNodes[4] = curNodes[6];
6554               uniqueNodes[5] = curNodes[7];
6555               isOk = true;
6556             }
6557             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
6558               uniqueNodes[0] = curNodes[0];
6559               uniqueNodes[1] = curNodes[2];
6560               uniqueNodes[2] = curNodes[3];
6561               uniqueNodes[3] = curNodes[1];
6562               uniqueNodes[4] = curNodes[6];
6563               uniqueNodes[5] = curNodes[7];
6564               isOk = true;
6565             }
6566             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
6567               uniqueNodes[0] = curNodes[0];
6568               uniqueNodes[1] = curNodes[1];
6569               uniqueNodes[2] = curNodes[2];
6570               uniqueNodes[3] = curNodes[4];
6571               uniqueNodes[4] = curNodes[5];
6572               uniqueNodes[5] = curNodes[7];
6573               isOk = true;
6574             }
6575             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
6576               uniqueNodes[0] = curNodes[0];
6577               uniqueNodes[1] = curNodes[1];
6578               uniqueNodes[2] = curNodes[3];
6579               uniqueNodes[3] = curNodes[4];
6580               uniqueNodes[4] = curNodes[2];
6581               uniqueNodes[5] = curNodes[7];
6582               isOk = true;
6583             }
6584             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
6585               uniqueNodes[0] = curNodes[0];
6586               uniqueNodes[1] = curNodes[1];
6587               uniqueNodes[2] = curNodes[2];
6588               uniqueNodes[3] = curNodes[4];
6589               uniqueNodes[4] = curNodes[5];
6590               uniqueNodes[5] = curNodes[3];
6591               isOk = true;
6592             }
6593           }
6594           if(nbRepl==4) {
6595             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
6596           }
6597           if(nbRepl==5) {
6598             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
6599           }
6600           break;
6601         }
6602         //////////////////////////////////// HEXAHEDRON
6603         isOk = false;
6604         SMDS_VolumeTool hexa (elem);
6605         hexa.SetExternalNormal();
6606         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
6607           //////////////////////// HEX ---> 1 tetrahedron
6608           for ( int iFace = 0; iFace < 6; iFace++ ) {
6609             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6610             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6611                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6612                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6613               // one face turns into a point ...
6614               int iOppFace = hexa.GetOppFaceIndex( iFace );
6615               ind = hexa.GetFaceNodesIndices( iOppFace );
6616               int nbStick = 0;
6617               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
6618                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6619                   nbStick++;
6620               }
6621               if ( nbStick == 1 ) {
6622                 // ... and the opposite one - into a triangle.
6623                 // set a top node
6624                 ind = hexa.GetFaceNodesIndices( iFace );
6625                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
6626                 isOk = true;
6627               }
6628               break;
6629             }
6630           }
6631         }
6632         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
6633           //////////////////////// HEX ---> 1 prism
6634           int nbTria = 0, iTria[3];
6635           const int *ind; // indices of face nodes
6636           // look for triangular faces
6637           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
6638             ind = hexa.GetFaceNodesIndices( iFace );
6639             TIDSortedNodeSet faceNodes;
6640             for ( iCur = 0; iCur < 4; iCur++ )
6641               faceNodes.insert( curNodes[ind[iCur]] );
6642             if ( faceNodes.size() == 3 )
6643               iTria[ nbTria++ ] = iFace;
6644           }
6645           // check if triangles are opposite
6646           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
6647           {
6648             isOk = true;
6649             // set nodes of the bottom triangle
6650             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
6651             vector<int> indB;
6652             for ( iCur = 0; iCur < 4; iCur++ )
6653               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
6654                 indB.push_back( ind[iCur] );
6655             if ( !hexa.IsForward() )
6656               std::swap( indB[0], indB[2] );
6657             for ( iCur = 0; iCur < 3; iCur++ )
6658               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
6659             // set nodes of the top triangle
6660             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
6661             for ( iCur = 0; iCur < 3; ++iCur )
6662               for ( int j = 0; j < 4; ++j )
6663                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
6664                 {
6665                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
6666                   break;
6667                 }
6668           }
6669           break;
6670         }
6671         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
6672           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
6673           for ( int iFace = 0; iFace < 6; iFace++ ) {
6674             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6675             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6676                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6677                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6678               // one face turns into a point ...
6679               int iOppFace = hexa.GetOppFaceIndex( iFace );
6680               ind = hexa.GetFaceNodesIndices( iOppFace );
6681               int nbStick = 0;
6682               iUnique = 2;  // reverse a tetrahedron 1 bottom
6683               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
6684                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6685                   nbStick++;
6686                 else if ( iUnique >= 0 )
6687                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6688               }
6689               if ( nbStick == 0 ) {
6690                 // ... and the opposite one is a quadrangle
6691                 // set a top node
6692                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
6693                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
6694                 nbUniqueNodes = 4;
6695                 // tetrahedron 2
6696                 SMDS_MeshElement* newElem =
6697                   aMesh->AddVolume(curNodes[ind[ 0 ]],
6698                                    curNodes[ind[ 3 ]],
6699                                    curNodes[ind[ 2 ]],
6700                                    curNodes[indTop[ 0 ]]);
6701                 myLastCreatedElems.Append(newElem);
6702                 if ( aShapeId )
6703                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
6704                 isOk = true;
6705               }
6706               break;
6707             }
6708           }
6709         }
6710         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
6711           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
6712           // find indices of quad and tri faces
6713           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
6714           for ( iFace = 0; iFace < 6; iFace++ ) {
6715             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6716             nodeSet.clear();
6717             for ( iCur = 0; iCur < 4; iCur++ )
6718               nodeSet.insert( curNodes[ind[ iCur ]] );
6719             nbUniqueNodes = nodeSet.size();
6720             if ( nbUniqueNodes == 3 )
6721               iTriFace[ nbTri++ ] = iFace;
6722             else if ( nbUniqueNodes == 4 )
6723               iQuadFace[ nbQuad++ ] = iFace;
6724           }
6725           if (nbQuad == 2 && nbTri == 4 &&
6726               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
6727             // 2 opposite quadrangles stuck with a diagonal;
6728             // sample groups of merged indices: (0-4)(2-6)
6729             // --------------------------------------------> 2 tetrahedrons
6730             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
6731             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
6732             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
6733             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
6734                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
6735               // stuck with 0-2 diagonal
6736               i0  = ind1[ 3 ];
6737               i1d = ind1[ 0 ];
6738               i2  = ind1[ 1 ];
6739               i3d = ind1[ 2 ];
6740               i0t = ind2[ 1 ];
6741               i2t = ind2[ 3 ];
6742             }
6743             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
6744                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
6745               // stuck with 1-3 diagonal
6746               i0  = ind1[ 0 ];
6747               i1d = ind1[ 1 ];
6748               i2  = ind1[ 2 ];
6749               i3d = ind1[ 3 ];
6750               i0t = ind2[ 0 ];
6751               i2t = ind2[ 1 ];
6752             }
6753             else {
6754               ASSERT(0);
6755             }
6756             // tetrahedron 1
6757             uniqueNodes[ 0 ] = curNodes [ i0 ];
6758             uniqueNodes[ 1 ] = curNodes [ i1d ];
6759             uniqueNodes[ 2 ] = curNodes [ i3d ];
6760             uniqueNodes[ 3 ] = curNodes [ i0t ];
6761             nbUniqueNodes = 4;
6762             // tetrahedron 2
6763             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
6764                                                          curNodes[ i2 ],
6765                                                          curNodes[ i3d ],
6766                                                          curNodes[ i2t ]);
6767             myLastCreatedElems.Append(newElem);
6768             if ( aShapeId )
6769               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6770             isOk = true;
6771           }
6772           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
6773                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
6774             // --------------------------------------------> prism
6775             // find 2 opposite triangles
6776             nbUniqueNodes = 6;
6777             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
6778               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
6779                 // find indices of kept and replaced nodes
6780                 // and fill unique nodes of 2 opposite triangles
6781                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
6782                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
6783                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
6784                 // fill unique nodes
6785                 iUnique = 0;
6786                 isOk = true;
6787                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
6788                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
6789                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
6790                   if ( n == nInit ) {
6791                     // iCur of a linked node of the opposite face (make normals co-directed):
6792                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
6793                     // check that correspondent corners of triangles are linked
6794                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
6795                       isOk = false;
6796                     else {
6797                       uniqueNodes[ iUnique ] = n;
6798                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
6799                       iUnique++;
6800                     }
6801                   }
6802                 }
6803                 break;
6804               }
6805             }
6806           }
6807         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
6808         else
6809         {
6810           MESSAGE("MergeNodes() removes hexahedron "<< elem);
6811         }
6812         break;
6813       } // HEXAHEDRON
6814
6815       default:
6816         isOk = false;
6817       } // switch ( nbNodes )
6818
6819     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
6820
6821     if ( isOk ) { // the elem remains valid after sticking nodes
6822       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
6823       {
6824         // Change nodes of polyedre
6825         const SMDS_VtkVolume* aPolyedre =
6826           dynamic_cast<const SMDS_VtkVolume*>( elem );
6827         if (aPolyedre) {
6828           int nbFaces = aPolyedre->NbFaces();
6829
6830           vector<const SMDS_MeshNode *> poly_nodes;
6831           vector<int> quantities (nbFaces);
6832
6833           for (int iface = 1; iface <= nbFaces; iface++) {
6834             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6835             quantities[iface - 1] = nbFaceNodes;
6836
6837             for (inode = 1; inode <= nbFaceNodes; inode++) {
6838               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
6839
6840               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
6841               if (nnIt != nodeNodeMap.end()) { // curNode sticks
6842                 curNode = (*nnIt).second;
6843               }
6844               poly_nodes.push_back(curNode);
6845             }
6846           }
6847           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
6848         }
6849       }
6850       else // replace non-polyhedron elements
6851       {
6852         const SMDSAbs_ElementType etyp = elem->GetType();
6853         const int elemId               = elem->GetID();
6854         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
6855         uniqueNodes.resize(nbUniqueNodes);
6856
6857         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
6858
6859         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
6860         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
6861         if ( sm && newElem )
6862           sm->AddElement( newElem );
6863         if ( elem != newElem )
6864           ReplaceElemInGroups( elem, newElem, aMesh );
6865       }
6866     }
6867     else {
6868       // Remove invalid regular element or invalid polygon
6869       rmElemIds.push_back( elem->GetID() );
6870     }
6871
6872   } // loop on elements
6873
6874   // Remove bad elements, then equal nodes (order important)
6875
6876   Remove( rmElemIds, false );
6877   Remove( rmNodeIds, true );
6878
6879 }
6880
6881
6882 // ========================================================
6883 // class   : SortableElement
6884 // purpose : allow sorting elements basing on their nodes
6885 // ========================================================
6886 class SortableElement : public set <const SMDS_MeshElement*>
6887 {
6888 public:
6889
6890   SortableElement( const SMDS_MeshElement* theElem )
6891   {
6892     myElem = theElem;
6893     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
6894     while ( nodeIt->more() )
6895       this->insert( nodeIt->next() );
6896   }
6897
6898   const SMDS_MeshElement* Get() const
6899   { return myElem; }
6900
6901   void Set(const SMDS_MeshElement* e) const
6902   { myElem = e; }
6903
6904
6905 private:
6906   mutable const SMDS_MeshElement* myElem;
6907 };
6908
6909 //=======================================================================
6910 //function : FindEqualElements
6911 //purpose  : Return list of group of elements built on the same nodes.
6912 //           Search among theElements or in the whole mesh if theElements is empty
6913 //=======================================================================
6914
6915 void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet &        theElements,
6916                                          TListOfListOfElementsID & theGroupsOfElementsID)
6917 {
6918   myLastCreatedElems.Clear();
6919   myLastCreatedNodes.Clear();
6920
6921   typedef map< SortableElement, int > TMapOfNodeSet;
6922   typedef list<int> TGroupOfElems;
6923
6924   if ( theElements.empty() )
6925   { // get all elements in the mesh
6926     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
6927     while ( eIt->more() )
6928       theElements.insert( theElements.end(), eIt->next());
6929   }
6930
6931   vector< TGroupOfElems > arrayOfGroups;
6932   TGroupOfElems groupOfElems;
6933   TMapOfNodeSet mapOfNodeSet;
6934
6935   TIDSortedElemSet::iterator elemIt = theElements.begin();
6936   for ( int i = 0, j=0; elemIt != theElements.end(); ++elemIt, ++j ) {
6937     const SMDS_MeshElement* curElem = *elemIt;
6938     SortableElement SE(curElem);
6939     int ind = -1;
6940     // check uniqueness
6941     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
6942     if( !(pp.second) ) {
6943       TMapOfNodeSet::iterator& itSE = pp.first;
6944       ind = (*itSE).second;
6945       arrayOfGroups[ind].push_back(curElem->GetID());
6946     }
6947     else {
6948       groupOfElems.clear();
6949       groupOfElems.push_back(curElem->GetID());
6950       arrayOfGroups.push_back(groupOfElems);
6951       i++;
6952     }
6953   }
6954
6955   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
6956   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
6957     groupOfElems = *groupIt;
6958     if ( groupOfElems.size() > 1 ) {
6959       groupOfElems.sort();
6960       theGroupsOfElementsID.push_back(groupOfElems);
6961     }
6962   }
6963 }
6964
6965 //=======================================================================
6966 //function : MergeElements
6967 //purpose  : In each given group, substitute all elements by the first one.
6968 //=======================================================================
6969
6970 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
6971 {
6972   myLastCreatedElems.Clear();
6973   myLastCreatedNodes.Clear();
6974
6975   typedef list<int> TListOfIDs;
6976   TListOfIDs rmElemIds; // IDs of elems to remove
6977
6978   SMESHDS_Mesh* aMesh = GetMeshDS();
6979
6980   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
6981   while ( groupsIt != theGroupsOfElementsID.end() ) {
6982     TListOfIDs& aGroupOfElemID = *groupsIt;
6983     aGroupOfElemID.sort();
6984     int elemIDToKeep = aGroupOfElemID.front();
6985     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
6986     aGroupOfElemID.pop_front();
6987     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
6988     while ( idIt != aGroupOfElemID.end() ) {
6989       int elemIDToRemove = *idIt;
6990       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
6991       // add the kept element in groups of removed one (PAL15188)
6992       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
6993       rmElemIds.push_back( elemIDToRemove );
6994       ++idIt;
6995     }
6996     ++groupsIt;
6997   }
6998
6999   Remove( rmElemIds, false );
7000 }
7001
7002 //=======================================================================
7003 //function : MergeEqualElements
7004 //purpose  : Remove all but one of elements built on the same nodes.
7005 //=======================================================================
7006
7007 void SMESH_MeshEditor::MergeEqualElements()
7008 {
7009   TIDSortedElemSet aMeshElements; /* empty input ==
7010                                      to merge equal elements in the whole mesh */
7011   TListOfListOfElementsID aGroupsOfElementsID;
7012   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7013   MergeElements(aGroupsOfElementsID);
7014 }
7015
7016 //=======================================================================
7017 //function : findAdjacentFace
7018 //purpose  :
7019 //=======================================================================
7020
7021 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7022                                                 const SMDS_MeshNode* n2,
7023                                                 const SMDS_MeshElement* elem)
7024 {
7025   TIDSortedElemSet elemSet, avoidSet;
7026   if ( elem )
7027     avoidSet.insert ( elem );
7028   return SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet );
7029 }
7030
7031 //=======================================================================
7032 //function : FindFreeBorder
7033 //purpose  :
7034 //=======================================================================
7035
7036 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7037
7038 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7039                                        const SMDS_MeshNode*             theSecondNode,
7040                                        const SMDS_MeshNode*             theLastNode,
7041                                        list< const SMDS_MeshNode* > &   theNodes,
7042                                        list< const SMDS_MeshElement* >& theFaces)
7043 {
7044   if ( !theFirstNode || !theSecondNode )
7045     return false;
7046   // find border face between theFirstNode and theSecondNode
7047   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7048   if ( !curElem )
7049     return false;
7050
7051   theFaces.push_back( curElem );
7052   theNodes.push_back( theFirstNode );
7053   theNodes.push_back( theSecondNode );
7054
7055   //vector<const SMDS_MeshNode*> nodes;
7056   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7057   TIDSortedElemSet foundElems;
7058   bool needTheLast = ( theLastNode != 0 );
7059
7060   while ( nStart != theLastNode ) {
7061     if ( nStart == theFirstNode )
7062       return !needTheLast;
7063
7064     // find all free border faces sharing form nStart
7065
7066     list< const SMDS_MeshElement* > curElemList;
7067     list< const SMDS_MeshNode* > nStartList;
7068     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7069     while ( invElemIt->more() ) {
7070       const SMDS_MeshElement* e = invElemIt->next();
7071       if ( e == curElem || foundElems.insert( e ).second ) {
7072         // get nodes
7073         int iNode = 0, nbNodes = e->NbNodes();
7074         //const SMDS_MeshNode* nodes[nbNodes+1];
7075         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7076
7077         if(e->IsQuadratic()) {
7078           const SMDS_VtkFace* F =
7079             dynamic_cast<const SMDS_VtkFace*>(e);
7080           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7081           // use special nodes iterator
7082           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7083           while( anIter->more() ) {
7084             nodes[ iNode++ ] = cast2Node(anIter->next());
7085           }
7086         }
7087         else {
7088           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7089           while ( nIt->more() )
7090             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7091         }
7092         nodes[ iNode ] = nodes[ 0 ];
7093         // check 2 links
7094         for ( iNode = 0; iNode < nbNodes; iNode++ )
7095           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7096                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7097               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7098           {
7099             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7100             curElemList.push_back( e );
7101           }
7102       }
7103     }
7104     // analyse the found
7105
7106     int nbNewBorders = curElemList.size();
7107     if ( nbNewBorders == 0 ) {
7108       // no free border furthermore
7109       return !needTheLast;
7110     }
7111     else if ( nbNewBorders == 1 ) {
7112       // one more element found
7113       nIgnore = nStart;
7114       nStart = nStartList.front();
7115       curElem = curElemList.front();
7116       theFaces.push_back( curElem );
7117       theNodes.push_back( nStart );
7118     }
7119     else {
7120       // several continuations found
7121       list< const SMDS_MeshElement* >::iterator curElemIt;
7122       list< const SMDS_MeshNode* >::iterator nStartIt;
7123       // check if one of them reached the last node
7124       if ( needTheLast ) {
7125         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7126              curElemIt!= curElemList.end();
7127              curElemIt++, nStartIt++ )
7128           if ( *nStartIt == theLastNode ) {
7129             theFaces.push_back( *curElemIt );
7130             theNodes.push_back( *nStartIt );
7131             return true;
7132           }
7133       }
7134       // find the best free border by the continuations
7135       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7136       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7137       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7138            curElemIt!= curElemList.end();
7139            curElemIt++, nStartIt++ )
7140       {
7141         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7142         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7143         // find one more free border
7144         if ( ! SMESH_MeshEditor::FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7145           cNL->clear();
7146           cFL->clear();
7147         }
7148         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7149           // choice: clear a worse one
7150           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7151           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7152           contNodes[ iWorse ].clear();
7153           contFaces[ iWorse ].clear();
7154         }
7155       }
7156       if ( contNodes[0].empty() && contNodes[1].empty() )
7157         return false;
7158
7159       // append the best free border
7160       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7161       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7162       theNodes.pop_back(); // remove nIgnore
7163       theNodes.pop_back(); // remove nStart
7164       theFaces.pop_back(); // remove curElem
7165       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7166       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7167       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7168       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7169       return true;
7170
7171     } // several continuations found
7172   } // while ( nStart != theLastNode )
7173
7174   return true;
7175 }
7176
7177 //=======================================================================
7178 //function : CheckFreeBorderNodes
7179 //purpose  : Return true if the tree nodes are on a free border
7180 //=======================================================================
7181
7182 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7183                                             const SMDS_MeshNode* theNode2,
7184                                             const SMDS_MeshNode* theNode3)
7185 {
7186   list< const SMDS_MeshNode* > nodes;
7187   list< const SMDS_MeshElement* > faces;
7188   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7189 }
7190
7191 //=======================================================================
7192 //function : SewFreeBorder
7193 //purpose  :
7194 //=======================================================================
7195
7196 SMESH_MeshEditor::Sew_Error
7197 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7198                                  const SMDS_MeshNode* theBordSecondNode,
7199                                  const SMDS_MeshNode* theBordLastNode,
7200                                  const SMDS_MeshNode* theSideFirstNode,
7201                                  const SMDS_MeshNode* theSideSecondNode,
7202                                  const SMDS_MeshNode* theSideThirdNode,
7203                                  const bool           theSideIsFreeBorder,
7204                                  const bool           toCreatePolygons,
7205                                  const bool           toCreatePolyedrs)
7206 {
7207   myLastCreatedElems.Clear();
7208   myLastCreatedNodes.Clear();
7209
7210   MESSAGE("::SewFreeBorder()");
7211   Sew_Error aResult = SEW_OK;
7212
7213   // ====================================
7214   //    find side nodes and elements
7215   // ====================================
7216
7217   list< const SMDS_MeshNode* > nSide[ 2 ];
7218   list< const SMDS_MeshElement* > eSide[ 2 ];
7219   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7220   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7221
7222   // Free border 1
7223   // --------------
7224   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7225                       nSide[0], eSide[0])) {
7226     MESSAGE(" Free Border 1 not found " );
7227     aResult = SEW_BORDER1_NOT_FOUND;
7228   }
7229   if (theSideIsFreeBorder) {
7230     // Free border 2
7231     // --------------
7232     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7233                         nSide[1], eSide[1])) {
7234       MESSAGE(" Free Border 2 not found " );
7235       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7236     }
7237   }
7238   if ( aResult != SEW_OK )
7239     return aResult;
7240
7241   if (!theSideIsFreeBorder) {
7242     // Side 2
7243     // --------------
7244
7245     // -------------------------------------------------------------------------
7246     // Algo:
7247     // 1. If nodes to merge are not coincident, move nodes of the free border
7248     //    from the coord sys defined by the direction from the first to last
7249     //    nodes of the border to the correspondent sys of the side 2
7250     // 2. On the side 2, find the links most co-directed with the correspondent
7251     //    links of the free border
7252     // -------------------------------------------------------------------------
7253
7254     // 1. Since sewing may break if there are volumes to split on the side 2,
7255     //    we wont move nodes but just compute new coordinates for them
7256     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7257     TNodeXYZMap nBordXYZ;
7258     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7259     list< const SMDS_MeshNode* >::iterator nBordIt;
7260
7261     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7262     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7263     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7264     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7265     double tol2 = 1.e-8;
7266     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7267     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7268       // Need node movement.
7269
7270       // find X and Z axes to create trsf
7271       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7272       gp_Vec X = Zs ^ Zb;
7273       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7274         // Zb || Zs
7275         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7276
7277       // coord systems
7278       gp_Ax3 toBordAx( Pb1, Zb, X );
7279       gp_Ax3 fromSideAx( Ps1, Zs, X );
7280       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7281       // set trsf
7282       gp_Trsf toBordSys, fromSide2Sys;
7283       toBordSys.SetTransformation( toBordAx );
7284       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7285       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7286
7287       // move
7288       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7289         const SMDS_MeshNode* n = *nBordIt;
7290         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7291         toBordSys.Transforms( xyz );
7292         fromSide2Sys.Transforms( xyz );
7293         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7294       }
7295     }
7296     else {
7297       // just insert nodes XYZ in the nBordXYZ map
7298       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7299         const SMDS_MeshNode* n = *nBordIt;
7300         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7301       }
7302     }
7303
7304     // 2. On the side 2, find the links most co-directed with the correspondent
7305     //    links of the free border
7306
7307     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7308     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7309     sideNodes.push_back( theSideFirstNode );
7310
7311     bool hasVolumes = false;
7312     LinkID_Gen aLinkID_Gen( GetMeshDS() );
7313     set<long> foundSideLinkIDs, checkedLinkIDs;
7314     SMDS_VolumeTool volume;
7315     //const SMDS_MeshNode* faceNodes[ 4 ];
7316
7317     const SMDS_MeshNode*    sideNode;
7318     const SMDS_MeshElement* sideElem;
7319     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7320     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7321     nBordIt = bordNodes.begin();
7322     nBordIt++;
7323     // border node position and border link direction to compare with
7324     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7325     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7326     // choose next side node by link direction or by closeness to
7327     // the current border node:
7328     bool searchByDir = ( *nBordIt != theBordLastNode );
7329     do {
7330       // find the next node on the Side 2
7331       sideNode = 0;
7332       double maxDot = -DBL_MAX, minDist = DBL_MAX;
7333       long linkID;
7334       checkedLinkIDs.clear();
7335       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7336
7337       // loop on inverse elements of current node (prevSideNode) on the Side 2
7338       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7339       while ( invElemIt->more() )
7340       {
7341         const SMDS_MeshElement* elem = invElemIt->next();
7342         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7343         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7344         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7345         bool isVolume = volume.Set( elem );
7346         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7347         if ( isVolume ) // --volume
7348           hasVolumes = true;
7349         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7350           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7351           if(elem->IsQuadratic()) {
7352             const SMDS_VtkFace* F =
7353               dynamic_cast<const SMDS_VtkFace*>(elem);
7354             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7355             // use special nodes iterator
7356             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7357             while( anIter->more() ) {
7358               nodes[ iNode ] = cast2Node(anIter->next());
7359               if ( nodes[ iNode++ ] == prevSideNode )
7360                 iPrevNode = iNode - 1;
7361             }
7362           }
7363           else {
7364             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7365             while ( nIt->more() ) {
7366               nodes[ iNode ] = cast2Node( nIt->next() );
7367               if ( nodes[ iNode++ ] == prevSideNode )
7368                 iPrevNode = iNode - 1;
7369             }
7370           }
7371           // there are 2 links to check
7372           nbNodes = 2;
7373         }
7374         else // --edge
7375           continue;
7376         // loop on links, to be precise, on the second node of links
7377         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7378           const SMDS_MeshNode* n = nodes[ iNode ];
7379           if ( isVolume ) {
7380             if ( !volume.IsLinked( n, prevSideNode ))
7381               continue;
7382           }
7383           else {
7384             if ( iNode ) // a node before prevSideNode
7385               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7386             else         // a node after prevSideNode
7387               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7388           }
7389           // check if this link was already used
7390           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7391           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7392           if (!isJustChecked &&
7393               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7394           {
7395             // test a link geometrically
7396             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
7397             bool linkIsBetter = false;
7398             double dot = 0.0, dist = 0.0;
7399             if ( searchByDir ) { // choose most co-directed link
7400               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
7401               linkIsBetter = ( dot > maxDot );
7402             }
7403             else { // choose link with the node closest to bordPos
7404               dist = ( nextXYZ - bordPos ).SquareModulus();
7405               linkIsBetter = ( dist < minDist );
7406             }
7407             if ( linkIsBetter ) {
7408               maxDot = dot;
7409               minDist = dist;
7410               linkID = iLink;
7411               sideNode = n;
7412               sideElem = elem;
7413             }
7414           }
7415         }
7416       } // loop on inverse elements of prevSideNode
7417
7418       if ( !sideNode ) {
7419         MESSAGE(" Cant find path by links of the Side 2 ");
7420         return SEW_BAD_SIDE_NODES;
7421       }
7422       sideNodes.push_back( sideNode );
7423       sideElems.push_back( sideElem );
7424       foundSideLinkIDs.insert ( linkID );
7425       prevSideNode = sideNode;
7426
7427       if ( *nBordIt == theBordLastNode )
7428         searchByDir = false;
7429       else {
7430         // find the next border link to compare with
7431         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
7432         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7433         // move to next border node if sideNode is before forward border node (bordPos)
7434         while ( *nBordIt != theBordLastNode && !searchByDir ) {
7435           prevBordNode = *nBordIt;
7436           nBordIt++;
7437           bordPos = nBordXYZ[ *nBordIt ];
7438           bordDir = bordPos - nBordXYZ[ prevBordNode ];
7439           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7440         }
7441       }
7442     }
7443     while ( sideNode != theSideSecondNode );
7444
7445     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
7446       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
7447       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
7448     }
7449   } // end nodes search on the side 2
7450
7451   // ============================
7452   // sew the border to the side 2
7453   // ============================
7454
7455   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
7456   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
7457
7458   TListOfListOfNodes nodeGroupsToMerge;
7459   if ( nbNodes[0] == nbNodes[1] ||
7460        ( theSideIsFreeBorder && !theSideThirdNode)) {
7461
7462     // all nodes are to be merged
7463
7464     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
7465          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
7466          nIt[0]++, nIt[1]++ )
7467     {
7468       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7469       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
7470       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
7471     }
7472   }
7473   else {
7474
7475     // insert new nodes into the border and the side to get equal nb of segments
7476
7477     // get normalized parameters of nodes on the borders
7478     //double param[ 2 ][ maxNbNodes ];
7479     double* param[ 2 ];
7480     param[0] = new double [ maxNbNodes ];
7481     param[1] = new double [ maxNbNodes ];
7482     int iNode, iBord;
7483     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7484       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7485       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
7486       const SMDS_MeshNode* nPrev = *nIt;
7487       double bordLength = 0;
7488       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7489         const SMDS_MeshNode* nCur = *nIt;
7490         gp_XYZ segment (nCur->X() - nPrev->X(),
7491                         nCur->Y() - nPrev->Y(),
7492                         nCur->Z() - nPrev->Z());
7493         double segmentLen = segment.Modulus();
7494         bordLength += segmentLen;
7495         param[ iBord ][ iNode ] = bordLength;
7496         nPrev = nCur;
7497       }
7498       // normalize within [0,1]
7499       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7500         param[ iBord ][ iNode ] /= bordLength;
7501       }
7502     }
7503
7504     // loop on border segments
7505     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7506     int i[ 2 ] = { 0, 0 };
7507     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7508     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7509
7510     TElemOfNodeListMap insertMap;
7511     TElemOfNodeListMap::iterator insertMapIt;
7512     // insertMap is
7513     // key:   elem to insert nodes into
7514     // value: 2 nodes to insert between + nodes to be inserted
7515     do {
7516       bool next[ 2 ] = { false, false };
7517
7518       // find min adjacent segment length after sewing
7519       double nextParam = 10., prevParam = 0;
7520       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7521         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7522           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7523         if ( i[ iBord ] > 0 )
7524           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7525       }
7526       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7527       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7528       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7529
7530       // choose to insert or to merge nodes
7531       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7532       if ( Abs( du ) <= minSegLen * 0.2 ) {
7533         // merge
7534         // ------
7535         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7536         const SMDS_MeshNode* n0 = *nIt[0];
7537         const SMDS_MeshNode* n1 = *nIt[1];
7538         nodeGroupsToMerge.back().push_back( n1 );
7539         nodeGroupsToMerge.back().push_back( n0 );
7540         // position of node of the border changes due to merge
7541         param[ 0 ][ i[0] ] += du;
7542         // move n1 for the sake of elem shape evaluation during insertion.
7543         // n1 will be removed by MergeNodes() anyway
7544         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
7545         next[0] = next[1] = true;
7546       }
7547       else {
7548         // insert
7549         // ------
7550         int intoBord = ( du < 0 ) ? 0 : 1;
7551         const SMDS_MeshElement* elem = *eIt[ intoBord ];
7552         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
7553         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
7554         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
7555         if ( intoBord == 1 ) {
7556           // move node of the border to be on a link of elem of the side
7557           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
7558           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
7559           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
7560           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
7561           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
7562         }
7563         insertMapIt = insertMap.find( elem );
7564         bool notFound = ( insertMapIt == insertMap.end() );
7565         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
7566         if ( otherLink ) {
7567           // insert into another link of the same element:
7568           // 1. perform insertion into the other link of the elem
7569           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7570           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
7571           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
7572           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
7573           // 2. perform insertion into the link of adjacent faces
7574           while (true) {
7575             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
7576             if ( adjElem )
7577               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
7578             else
7579               break;
7580           }
7581           if (toCreatePolyedrs) {
7582             // perform insertion into the links of adjacent volumes
7583             UpdateVolumes(n12, n22, nodeList);
7584           }
7585           // 3. find an element appeared on n1 and n2 after the insertion
7586           insertMap.erase( elem );
7587           elem = findAdjacentFace( n1, n2, 0 );
7588         }
7589         if ( notFound || otherLink ) {
7590           // add element and nodes of the side into the insertMap
7591           insertMapIt = insertMap.insert
7592             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
7593           (*insertMapIt).second.push_back( n1 );
7594           (*insertMapIt).second.push_back( n2 );
7595         }
7596         // add node to be inserted into elem
7597         (*insertMapIt).second.push_back( nIns );
7598         next[ 1 - intoBord ] = true;
7599       }
7600
7601       // go to the next segment
7602       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7603         if ( next[ iBord ] ) {
7604           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
7605             eIt[ iBord ]++;
7606           nPrev[ iBord ] = *nIt[ iBord ];
7607           nIt[ iBord ]++; i[ iBord ]++;
7608         }
7609       }
7610     }
7611     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
7612
7613     // perform insertion of nodes into elements
7614
7615     for (insertMapIt = insertMap.begin();
7616          insertMapIt != insertMap.end();
7617          insertMapIt++ )
7618     {
7619       const SMDS_MeshElement* elem = (*insertMapIt).first;
7620       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7621       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
7622       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
7623
7624       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
7625
7626       if ( !theSideIsFreeBorder ) {
7627         // look for and insert nodes into the faces adjacent to elem
7628         while (true) {
7629           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
7630           if ( adjElem )
7631             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
7632           else
7633             break;
7634         }
7635       }
7636       if (toCreatePolyedrs) {
7637         // perform insertion into the links of adjacent volumes
7638         UpdateVolumes(n1, n2, nodeList);
7639       }
7640     }
7641
7642     delete param[0];
7643     delete param[1];
7644   } // end: insert new nodes
7645
7646   MergeNodes ( nodeGroupsToMerge );
7647
7648   return aResult;
7649 }
7650
7651 //=======================================================================
7652 //function : InsertNodesIntoLink
7653 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
7654 //           and theBetweenNode2 and split theElement
7655 //=======================================================================
7656
7657 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
7658                                            const SMDS_MeshNode*        theBetweenNode1,
7659                                            const SMDS_MeshNode*        theBetweenNode2,
7660                                            list<const SMDS_MeshNode*>& theNodesToInsert,
7661                                            const bool                  toCreatePoly)
7662 {
7663   if ( theFace->GetType() != SMDSAbs_Face ) return;
7664
7665   // find indices of 2 link nodes and of the rest nodes
7666   int iNode = 0, il1, il2, i3, i4;
7667   il1 = il2 = i3 = i4 = -1;
7668   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
7669   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
7670
7671   if(theFace->IsQuadratic()) {
7672     const SMDS_VtkFace* F =
7673       dynamic_cast<const SMDS_VtkFace*>(theFace);
7674     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7675     // use special nodes iterator
7676     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7677     while( anIter->more() ) {
7678       const SMDS_MeshNode* n = cast2Node(anIter->next());
7679       if ( n == theBetweenNode1 )
7680         il1 = iNode;
7681       else if ( n == theBetweenNode2 )
7682         il2 = iNode;
7683       else if ( i3 < 0 )
7684         i3 = iNode;
7685       else
7686         i4 = iNode;
7687       nodes[ iNode++ ] = n;
7688     }
7689   }
7690   else {
7691     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7692     while ( nodeIt->more() ) {
7693       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7694       if ( n == theBetweenNode1 )
7695         il1 = iNode;
7696       else if ( n == theBetweenNode2 )
7697         il2 = iNode;
7698       else if ( i3 < 0 )
7699         i3 = iNode;
7700       else
7701         i4 = iNode;
7702       nodes[ iNode++ ] = n;
7703     }
7704   }
7705   if ( il1 < 0 || il2 < 0 || i3 < 0 )
7706     return ;
7707
7708   // arrange link nodes to go one after another regarding the face orientation
7709   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
7710   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
7711   if ( reverse ) {
7712     iNode = il1;
7713     il1 = il2;
7714     il2 = iNode;
7715     aNodesToInsert.reverse();
7716   }
7717   // check that not link nodes of a quadrangles are in good order
7718   int nbFaceNodes = theFace->NbNodes();
7719   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
7720     iNode = i3;
7721     i3 = i4;
7722     i4 = iNode;
7723   }
7724
7725   if (toCreatePoly || theFace->IsPoly()) {
7726
7727     iNode = 0;
7728     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
7729
7730     // add nodes of face up to first node of link
7731     bool isFLN = false;
7732
7733     if(theFace->IsQuadratic()) {
7734       const SMDS_VtkFace* F =
7735         dynamic_cast<const SMDS_VtkFace*>(theFace);
7736       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7737       // use special nodes iterator
7738       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7739       while( anIter->more()  && !isFLN ) {
7740         const SMDS_MeshNode* n = cast2Node(anIter->next());
7741         poly_nodes[iNode++] = n;
7742         if (n == nodes[il1]) {
7743           isFLN = true;
7744         }
7745       }
7746       // add nodes to insert
7747       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7748       for (; nIt != aNodesToInsert.end(); nIt++) {
7749         poly_nodes[iNode++] = *nIt;
7750       }
7751       // add nodes of face starting from last node of link
7752       while ( anIter->more() ) {
7753         poly_nodes[iNode++] = cast2Node(anIter->next());
7754       }
7755     }
7756     else {
7757       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7758       while ( nodeIt->more() && !isFLN ) {
7759         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7760         poly_nodes[iNode++] = n;
7761         if (n == nodes[il1]) {
7762           isFLN = true;
7763         }
7764       }
7765       // add nodes to insert
7766       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7767       for (; nIt != aNodesToInsert.end(); nIt++) {
7768         poly_nodes[iNode++] = *nIt;
7769       }
7770       // add nodes of face starting from last node of link
7771       while ( nodeIt->more() ) {
7772         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7773         poly_nodes[iNode++] = n;
7774       }
7775     }
7776
7777     // edit or replace the face
7778     SMESHDS_Mesh *aMesh = GetMeshDS();
7779
7780     if (theFace->IsPoly()) {
7781       aMesh->ChangePolygonNodes(theFace, poly_nodes);
7782     }
7783     else {
7784       int aShapeId = FindShape( theFace );
7785
7786       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7787       myLastCreatedElems.Append(newElem);
7788       if ( aShapeId && newElem )
7789         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7790
7791       aMesh->RemoveElement(theFace);
7792     }
7793     return;
7794   }
7795
7796   SMESHDS_Mesh *aMesh = GetMeshDS();
7797   if( !theFace->IsQuadratic() ) {
7798
7799     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
7800     int nbLinkNodes = 2 + aNodesToInsert.size();
7801     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
7802     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
7803     linkNodes[ 0 ] = nodes[ il1 ];
7804     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
7805     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7806     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7807       linkNodes[ iNode++ ] = *nIt;
7808     }
7809     // decide how to split a quadrangle: compare possible variants
7810     // and choose which of splits to be a quadrangle
7811     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
7812     if ( nbFaceNodes == 3 ) {
7813       iBestQuad = nbSplits;
7814       i4 = i3;
7815     }
7816     else if ( nbFaceNodes == 4 ) {
7817       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
7818       double aBestRate = DBL_MAX;
7819       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
7820         i1 = 0; i2 = 1;
7821         double aBadRate = 0;
7822         // evaluate elements quality
7823         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
7824           if ( iSplit == iQuad ) {
7825             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
7826                                    linkNodes[ i2++ ],
7827                                    nodes[ i3 ],
7828                                    nodes[ i4 ]);
7829             aBadRate += getBadRate( &quad, aCrit );
7830           }
7831           else {
7832             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
7833                                    linkNodes[ i2++ ],
7834                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
7835             aBadRate += getBadRate( &tria, aCrit );
7836           }
7837         }
7838         // choice
7839         if ( aBadRate < aBestRate ) {
7840           iBestQuad = iQuad;
7841           aBestRate = aBadRate;
7842         }
7843       }
7844     }
7845
7846     // create new elements
7847     int aShapeId = FindShape( theFace );
7848
7849     i1 = 0; i2 = 1;
7850     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
7851       SMDS_MeshElement* newElem = 0;
7852       if ( iSplit == iBestQuad )
7853         newElem = aMesh->AddFace (linkNodes[ i1++ ],
7854                                   linkNodes[ i2++ ],
7855                                   nodes[ i3 ],
7856                                   nodes[ i4 ]);
7857       else
7858         newElem = aMesh->AddFace (linkNodes[ i1++ ],
7859                                   linkNodes[ i2++ ],
7860                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
7861       myLastCreatedElems.Append(newElem);
7862       if ( aShapeId && newElem )
7863         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7864     }
7865
7866     // change nodes of theFace
7867     const SMDS_MeshNode* newNodes[ 4 ];
7868     newNodes[ 0 ] = linkNodes[ i1 ];
7869     newNodes[ 1 ] = linkNodes[ i2 ];
7870     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
7871     newNodes[ 3 ] = nodes[ i4 ];
7872     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
7873     const SMDS_MeshElement* newElem = 0;
7874     if (iSplit == iBestQuad)
7875       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
7876     else
7877       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
7878     myLastCreatedElems.Append(newElem);
7879     if ( aShapeId && newElem )
7880       aMesh->SetMeshElementOnShape( newElem, aShapeId );
7881 } // end if(!theFace->IsQuadratic())
7882   else { // theFace is quadratic
7883     // we have to split theFace on simple triangles and one simple quadrangle
7884     int tmp = il1/2;
7885     int nbshift = tmp*2;
7886     // shift nodes in nodes[] by nbshift
7887     int i,j;
7888     for(i=0; i<nbshift; i++) {
7889       const SMDS_MeshNode* n = nodes[0];
7890       for(j=0; j<nbFaceNodes-1; j++) {
7891         nodes[j] = nodes[j+1];
7892       }
7893       nodes[nbFaceNodes-1] = n;
7894     }
7895     il1 = il1 - nbshift;
7896     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
7897     //   n0      n1     n2    n0      n1     n2
7898     //     +-----+-----+        +-----+-----+
7899     //      \         /         |           |
7900     //       \       /          |           |
7901     //      n5+     +n3       n7+           +n3
7902     //         \   /            |           |
7903     //          \ /             |           |
7904     //           +              +-----+-----+
7905     //           n4           n6      n5     n4
7906
7907     // create new elements
7908     int aShapeId = FindShape( theFace );
7909
7910     int n1,n2,n3;
7911     if(nbFaceNodes==6) { // quadratic triangle
7912       SMDS_MeshElement* newElem =
7913         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7914       myLastCreatedElems.Append(newElem);
7915       if ( aShapeId && newElem )
7916         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7917       if(theFace->IsMediumNode(nodes[il1])) {
7918         // create quadrangle
7919         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
7920         myLastCreatedElems.Append(newElem);
7921         if ( aShapeId && newElem )
7922           aMesh->SetMeshElementOnShape( newElem, aShapeId );
7923         n1 = 1;
7924         n2 = 2;
7925         n3 = 3;
7926       }
7927       else {
7928         // create quadrangle
7929         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
7930         myLastCreatedElems.Append(newElem);
7931         if ( aShapeId && newElem )
7932           aMesh->SetMeshElementOnShape( newElem, aShapeId );
7933         n1 = 0;
7934         n2 = 1;
7935         n3 = 5;
7936       }
7937     }
7938     else { // nbFaceNodes==8 - quadratic quadrangle
7939       SMDS_MeshElement* newElem =
7940         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7941       myLastCreatedElems.Append(newElem);
7942       if ( aShapeId && newElem )
7943         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7944       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
7945       myLastCreatedElems.Append(newElem);
7946       if ( aShapeId && newElem )
7947         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7948       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
7949       myLastCreatedElems.Append(newElem);
7950       if ( aShapeId && newElem )
7951         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7952       if(theFace->IsMediumNode(nodes[il1])) {
7953         // create quadrangle
7954         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
7955         myLastCreatedElems.Append(newElem);
7956         if ( aShapeId && newElem )
7957           aMesh->SetMeshElementOnShape( newElem, aShapeId );
7958         n1 = 1;
7959         n2 = 2;
7960         n3 = 3;
7961       }
7962       else {
7963         // create quadrangle
7964         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
7965         myLastCreatedElems.Append(newElem);
7966         if ( aShapeId && newElem )
7967           aMesh->SetMeshElementOnShape( newElem, aShapeId );
7968         n1 = 0;
7969         n2 = 1;
7970         n3 = 7;
7971       }
7972     }
7973     // create needed triangles using n1,n2,n3 and inserted nodes
7974     int nbn = 2 + aNodesToInsert.size();
7975     //const SMDS_MeshNode* aNodes[nbn];
7976     vector<const SMDS_MeshNode*> aNodes(nbn);
7977     aNodes[0] = nodes[n1];
7978     aNodes[nbn-1] = nodes[n2];
7979     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7980     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7981       aNodes[iNode++] = *nIt;
7982     }
7983     for(i=1; i<nbn; i++) {
7984       SMDS_MeshElement* newElem =
7985         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
7986       myLastCreatedElems.Append(newElem);
7987       if ( aShapeId && newElem )
7988         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7989     }
7990   }
7991   // remove old face
7992   aMesh->RemoveElement(theFace);
7993 }
7994
7995 //=======================================================================
7996 //function : UpdateVolumes
7997 //purpose  :
7998 //=======================================================================
7999 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8000                                       const SMDS_MeshNode*        theBetweenNode2,
8001                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8002 {
8003   myLastCreatedElems.Clear();
8004   myLastCreatedNodes.Clear();
8005
8006   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8007   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8008     const SMDS_MeshElement* elem = invElemIt->next();
8009
8010     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8011     SMDS_VolumeTool aVolume (elem);
8012     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8013       continue;
8014
8015     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8016     int iface, nbFaces = aVolume.NbFaces();
8017     vector<const SMDS_MeshNode *> poly_nodes;
8018     vector<int> quantities (nbFaces);
8019
8020     for (iface = 0; iface < nbFaces; iface++) {
8021       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8022       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8023       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8024
8025       for (int inode = 0; inode < nbFaceNodes; inode++) {
8026         poly_nodes.push_back(faceNodes[inode]);
8027
8028         if (nbInserted == 0) {
8029           if (faceNodes[inode] == theBetweenNode1) {
8030             if (faceNodes[inode + 1] == theBetweenNode2) {
8031               nbInserted = theNodesToInsert.size();
8032
8033               // add nodes to insert
8034               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8035               for (; nIt != theNodesToInsert.end(); nIt++) {
8036                 poly_nodes.push_back(*nIt);
8037               }
8038             }
8039           }
8040           else if (faceNodes[inode] == theBetweenNode2) {
8041             if (faceNodes[inode + 1] == theBetweenNode1) {
8042               nbInserted = theNodesToInsert.size();
8043
8044               // add nodes to insert in reversed order
8045               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8046               nIt--;
8047               for (; nIt != theNodesToInsert.begin(); nIt--) {
8048                 poly_nodes.push_back(*nIt);
8049               }
8050               poly_nodes.push_back(*nIt);
8051             }
8052           }
8053           else {
8054           }
8055         }
8056       }
8057       quantities[iface] = nbFaceNodes + nbInserted;
8058     }
8059
8060     // Replace or update the volume
8061     SMESHDS_Mesh *aMesh = GetMeshDS();
8062
8063     if (elem->IsPoly()) {
8064       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8065
8066     }
8067     else {
8068       int aShapeId = FindShape( elem );
8069
8070       SMDS_MeshElement* newElem =
8071         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8072       myLastCreatedElems.Append(newElem);
8073       if (aShapeId && newElem)
8074         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8075
8076       aMesh->RemoveElement(elem);
8077     }
8078   }
8079 }
8080
8081 namespace
8082 {
8083   //================================================================================
8084   /*!
8085    * \brief Transform any volume into data of SMDSEntity_Polyhedra
8086    */
8087   //================================================================================
8088
8089   void volumeToPolyhedron( const SMDS_MeshElement*         elem,
8090                            vector<const SMDS_MeshNode *> & nodes,
8091                            vector<int> &                   nbNodeInFaces )
8092   {
8093     nodes.clear();
8094     nbNodeInFaces.clear();
8095     SMDS_VolumeTool vTool ( elem );
8096     for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
8097     {
8098       const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
8099       nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
8100       nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
8101     }
8102   }
8103 }
8104
8105 //=======================================================================
8106 /*!
8107  * \brief Convert elements contained in a submesh to quadratic
8108  * \return int - nb of checked elements
8109  */
8110 //=======================================================================
8111
8112 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8113                                              SMESH_MesherHelper& theHelper,
8114                                              const bool          theForce3d)
8115 {
8116   int nbElem = 0;
8117   if( !theSm ) return nbElem;
8118
8119   vector<int> nbNodeInFaces;
8120   vector<const SMDS_MeshNode *> nodes;
8121   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8122   while(ElemItr->more())
8123   {
8124     nbElem++;
8125     const SMDS_MeshElement* elem = ElemItr->next();
8126     if( !elem ) continue;
8127
8128     // analyse a necessity of conversion
8129     const SMDSAbs_ElementType aType = elem->GetType();
8130     if ( aType < SMDSAbs_Edge || aType > SMDSAbs_Volume )
8131       continue;
8132     const SMDSAbs_EntityType aGeomType = elem->GetEntityType();
8133     bool hasCentralNodes = false;
8134     if ( elem->IsQuadratic() )
8135     {
8136       bool alreadyOK;
8137       switch ( aGeomType ) {
8138       case SMDSEntity_Quad_Triangle:
8139       case SMDSEntity_Quad_Quadrangle:
8140       case SMDSEntity_Quad_Hexa:
8141         alreadyOK = !theHelper.GetIsBiQuadratic(); break;
8142
8143       case SMDSEntity_BiQuad_Triangle:
8144       case SMDSEntity_BiQuad_Quadrangle:
8145       case SMDSEntity_TriQuad_Hexa:
8146         alreadyOK = theHelper.GetIsBiQuadratic();
8147         hasCentralNodes = true;
8148         break;
8149       default:
8150         alreadyOK = true;
8151       }
8152       // take into account already present modium nodes
8153       switch ( aType ) {
8154       case SMDSAbs_Volume:
8155         theHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( elem )); break;
8156       case SMDSAbs_Face:
8157         theHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem )); break;
8158       case SMDSAbs_Edge:
8159         theHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( elem )); break;
8160       default:;
8161       }
8162       if ( alreadyOK )
8163         continue;
8164     }
8165     // get elem data needed to re-create it
8166     //
8167     const int id      = elem->GetID();
8168     const int nbNodes = elem->NbCornerNodes();
8169     nodes.assign(elem->begin_nodes(), elem->end_nodes());
8170     if ( aGeomType == SMDSEntity_Polyhedra )
8171       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
8172     else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
8173       volumeToPolyhedron( elem, nodes, nbNodeInFaces );
8174
8175     // remove a linear element
8176     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
8177
8178     // remove central nodes of biquadratic elements (biquad->quad convertion)
8179     if ( hasCentralNodes )
8180       for ( size_t i = nbNodes * 2; i < nodes.size(); ++i )
8181         if ( nodes[i]->NbInverseElements() == 0 )
8182           GetMeshDS()->RemoveFreeNode( nodes[i], theSm, /*fromGroups=*/true );
8183
8184     const SMDS_MeshElement* NewElem = 0;
8185
8186     switch( aType )
8187     {
8188     case SMDSAbs_Edge :
8189       {
8190         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8191         break;
8192       }
8193     case SMDSAbs_Face :
8194       {
8195         switch(nbNodes)
8196         {
8197         case 3:
8198           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8199           break;
8200         case 4:
8201           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8202           break;
8203         default:
8204           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
8205         }
8206         break;
8207       }
8208     case SMDSAbs_Volume :
8209       {
8210         switch( aGeomType )
8211         {
8212         case SMDSEntity_Tetra:
8213           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8214           break;
8215         case SMDSEntity_Pyramid:
8216           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
8217           break;
8218         case SMDSEntity_Penta:
8219           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
8220           break;
8221         case SMDSEntity_Hexa:
8222         case SMDSEntity_Quad_Hexa:
8223         case SMDSEntity_TriQuad_Hexa:
8224           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8225                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8226           break;
8227         case SMDSEntity_Hexagonal_Prism:
8228         default:
8229           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8230         }
8231         break;
8232       }
8233     default :
8234       continue;
8235     }
8236     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8237     if( NewElem && NewElem->getshapeId() < 1 )
8238       theSm->AddElement( NewElem );
8239   }
8240   return nbElem;
8241 }
8242 //=======================================================================
8243 //function : ConvertToQuadratic
8244 //purpose  :
8245 //=======================================================================
8246
8247 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad)
8248 {
8249   SMESHDS_Mesh* meshDS = GetMeshDS();
8250
8251   SMESH_MesherHelper aHelper(*myMesh);
8252
8253   aHelper.SetIsQuadratic( true );
8254   aHelper.SetIsBiQuadratic( theToBiQuad );
8255   aHelper.SetElementsOnShape(true);
8256
8257   // convert elements assigned to sub-meshes
8258   int nbCheckedElems = 0;
8259   if ( myMesh->HasShapeToMesh() )
8260   {
8261     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8262     {
8263       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8264       while ( smIt->more() ) {
8265         SMESH_subMesh* sm = smIt->next();
8266         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8267           aHelper.SetSubShape( sm->GetSubShape() );
8268           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8269         }
8270       }
8271     }
8272   }
8273
8274   // convert elements NOT assigned to sub-meshes
8275   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8276   if ( nbCheckedElems < totalNbElems ) // not all elements are in sub-meshes
8277   {
8278     aHelper.SetElementsOnShape(false);
8279     SMESHDS_SubMesh *smDS = 0;
8280
8281     // convert edges
8282     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8283     while( aEdgeItr->more() )
8284     {
8285       const SMDS_MeshEdge* edge = aEdgeItr->next();
8286       if ( !edge->IsQuadratic() )
8287       {
8288         int                  id = edge->GetID();
8289         const SMDS_MeshNode* n1 = edge->GetNode(0);
8290         const SMDS_MeshNode* n2 = edge->GetNode(1);
8291
8292         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
8293
8294         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8295         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8296       }
8297       else
8298       {
8299         aHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( edge ));
8300       }
8301     }
8302
8303     // convert faces
8304     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8305     while( aFaceItr->more() )
8306     {
8307       const SMDS_MeshFace* face = aFaceItr->next();
8308       if ( !face ) continue;
8309       
8310       const SMDSAbs_EntityType type = face->GetEntityType();
8311       bool alreadyOK;
8312       switch( type )
8313       {
8314       case SMDSEntity_Quad_Triangle:
8315       case SMDSEntity_Quad_Quadrangle:
8316         alreadyOK = !theToBiQuad;
8317         aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
8318         break;
8319       case SMDSEntity_BiQuad_Triangle:
8320       case SMDSEntity_BiQuad_Quadrangle:
8321         alreadyOK = theToBiQuad;
8322         aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
8323         break;
8324       default: alreadyOK = false;
8325       }
8326       if ( alreadyOK )
8327         continue;
8328
8329       const int id = face->GetID();
8330       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
8331
8332       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
8333
8334       SMDS_MeshFace * NewFace = 0;
8335       switch( type )
8336       {
8337       case SMDSEntity_Triangle:
8338       case SMDSEntity_Quad_Triangle:
8339       case SMDSEntity_BiQuad_Triangle:
8340         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8341         if ( nodes.size() == 7 && nodes[6]->NbInverseElements() == 0 ) // rm a central node
8342           GetMeshDS()->RemoveFreeNode( nodes[6], /*sm=*/0, /*fromGroups=*/true );
8343         break;
8344
8345       case SMDSEntity_Quadrangle:
8346       case SMDSEntity_Quad_Quadrangle:
8347       case SMDSEntity_BiQuad_Quadrangle:
8348         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8349         if ( nodes.size() == 9 && nodes[8]->NbInverseElements() == 0 ) // rm a central node
8350           GetMeshDS()->RemoveFreeNode( nodes[8], /*sm=*/0, /*fromGroups=*/true );
8351         break;
8352
8353       default:;
8354         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
8355       }
8356       ReplaceElemInGroups( face, NewFace, GetMeshDS());
8357     }
8358
8359     // convert volumes
8360     vector<int> nbNodeInFaces;
8361     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8362     while(aVolumeItr->more())
8363     {
8364       const SMDS_MeshVolume* volume = aVolumeItr->next();
8365       if ( !volume ) continue;
8366
8367       const SMDSAbs_EntityType type = volume->GetEntityType();
8368       if (( theToBiQuad  && type == SMDSEntity_TriQuad_Hexa ) ||
8369           ( !theToBiQuad && type == SMDSEntity_Quad_Hexa ))
8370       {
8371         aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume ));
8372         continue;
8373       }
8374       const int id = volume->GetID();
8375       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
8376       if ( type == SMDSEntity_Polyhedra )
8377         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
8378       else if ( type == SMDSEntity_Hexagonal_Prism )
8379         volumeToPolyhedron( volume, nodes, nbNodeInFaces );
8380
8381       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
8382
8383       SMDS_MeshVolume * NewVolume = 0;
8384       switch ( type )
8385       {
8386       case SMDSEntity_Tetra:
8387         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
8388         break;
8389       case SMDSEntity_Hexa:
8390       case SMDSEntity_Quad_Hexa:
8391       case SMDSEntity_TriQuad_Hexa:
8392         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8393                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8394         for ( size_t i = 20; i < nodes.size(); ++i ) // rm central nodes
8395           if ( nodes[i]->NbInverseElements() == 0 )
8396             GetMeshDS()->RemoveFreeNode( nodes[i], /*sm=*/0, /*fromGroups=*/true );
8397         break;
8398       case SMDSEntity_Pyramid:
8399         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8400                                       nodes[3], nodes[4], id, theForce3d);
8401         break;
8402       case SMDSEntity_Penta:
8403         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8404                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
8405         break;
8406       case SMDSEntity_Hexagonal_Prism:
8407       default:
8408         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8409       }
8410       ReplaceElemInGroups(volume, NewVolume, meshDS);
8411     }
8412   }
8413
8414   if ( !theForce3d )
8415   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8416     // aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8417     // aHelper.FixQuadraticElements(myError);
8418     SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
8419   }
8420 }
8421
8422 //================================================================================
8423 /*!
8424  * \brief Makes given elements quadratic
8425  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
8426  *  \param theElements - elements to make quadratic
8427  */
8428 //================================================================================
8429
8430 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
8431                                           TIDSortedElemSet& theElements,
8432                                           const bool        theToBiQuad)
8433 {
8434   if ( theElements.empty() ) return;
8435
8436   // we believe that all theElements are of the same type
8437   const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
8438
8439   // get all nodes shared by theElements
8440   TIDSortedNodeSet allNodes;
8441   TIDSortedElemSet::iterator eIt = theElements.begin();
8442   for ( ; eIt != theElements.end(); ++eIt )
8443     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
8444
8445   // complete theElements with elements of lower dim whose all nodes are in allNodes
8446
8447   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
8448   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
8449   TIDSortedNodeSet::iterator nIt = allNodes.begin();
8450   for ( ; nIt != allNodes.end(); ++nIt )
8451   {
8452     const SMDS_MeshNode* n = *nIt;
8453     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
8454     while ( invIt->more() )
8455     {
8456       const SMDS_MeshElement*      e = invIt->next();
8457       const SMDSAbs_ElementType type = e->GetType();
8458       if ( e->IsQuadratic() )
8459       {
8460         quadAdjacentElems[ type ].insert( e );
8461
8462         bool alreadyOK;
8463         switch ( e->GetEntityType() ) {
8464         case SMDSEntity_Quad_Triangle:
8465         case SMDSEntity_Quad_Quadrangle:
8466         case SMDSEntity_Quad_Hexa:         alreadyOK = !theToBiQuad; break;
8467         case SMDSEntity_BiQuad_Triangle:
8468         case SMDSEntity_BiQuad_Quadrangle:
8469         case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; break;
8470         default:                           alreadyOK = true;
8471         }
8472         if ( alreadyOK )
8473           continue;
8474       }
8475       if ( type >= elemType )
8476         continue; // same type or more complex linear element
8477
8478       if ( !checkedAdjacentElems[ type ].insert( e ).second )
8479         continue; // e is already checked
8480
8481       // check nodes
8482       bool allIn = true;
8483       SMDS_NodeIteratorPtr nodeIt = e->nodeIterator();
8484       while ( nodeIt->more() && allIn )
8485         allIn = allNodes.count( nodeIt->next() );
8486       if ( allIn )
8487         theElements.insert(e );
8488     }
8489   }
8490
8491   SMESH_MesherHelper helper(*myMesh);
8492   helper.SetIsQuadratic( true );
8493   helper.SetIsBiQuadratic( theToBiQuad );
8494
8495   // add links of quadratic adjacent elements to the helper
8496
8497   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
8498     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
8499           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
8500     {
8501       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
8502     }
8503   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
8504     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
8505           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
8506     {
8507       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
8508     }
8509   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
8510     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
8511           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
8512     {
8513       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
8514     }
8515
8516   // make quadratic (or bi-tri-quadratic) elements instead of linear ones
8517
8518   SMESHDS_Mesh*  meshDS = GetMeshDS();
8519   SMESHDS_SubMesh* smDS = 0;
8520   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
8521   {
8522     const SMDS_MeshElement* elem = *eIt;
8523
8524     bool alreadyOK;
8525     int nbCentralNodes = 0;
8526     switch ( elem->GetEntityType() ) {
8527       // linear convertible
8528     case SMDSEntity_Edge:
8529     case SMDSEntity_Triangle:
8530     case SMDSEntity_Quadrangle:
8531     case SMDSEntity_Tetra:
8532     case SMDSEntity_Pyramid:
8533     case SMDSEntity_Hexa:
8534     case SMDSEntity_Penta:             alreadyOK = false;       nbCentralNodes = 0; break;
8535       // quadratic that can become bi-quadratic
8536     case SMDSEntity_Quad_Triangle:
8537     case SMDSEntity_Quad_Quadrangle:
8538     case SMDSEntity_Quad_Hexa:         alreadyOK =!theToBiQuad; nbCentralNodes = 0; break;
8539       // bi-quadratic
8540     case SMDSEntity_BiQuad_Triangle:
8541     case SMDSEntity_BiQuad_Quadrangle: alreadyOK = theToBiQuad; nbCentralNodes = 1; break;
8542     case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; nbCentralNodes = 7; break;
8543       // the rest
8544     default:                           alreadyOK = true;
8545     }
8546     if ( alreadyOK ) continue;
8547
8548     const SMDSAbs_ElementType type = elem->GetType();
8549     const int                   id = elem->GetID();
8550     const int              nbNodes = elem->NbCornerNodes();
8551     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
8552
8553     helper.SetSubShape( elem->getshapeId() );
8554
8555     if ( !smDS || !smDS->Contains( elem ))
8556       smDS = meshDS->MeshElements( elem->getshapeId() );
8557     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
8558
8559     SMDS_MeshElement * newElem = 0;
8560     switch( nbNodes )
8561     {
8562     case 4: // cases for most frequently used element types go first (for optimization)
8563       if ( type == SMDSAbs_Volume )
8564         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8565       else
8566         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8567       break;
8568     case 8:
8569       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8570                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8571       break;
8572     case 3:
8573       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
8574       break;
8575     case 2:
8576       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8577       break;
8578     case 5:
8579       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8580                                  nodes[4], id, theForce3d);
8581       break;
8582     case 6:
8583       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8584                                  nodes[4], nodes[5], id, theForce3d);
8585       break;
8586     default:;
8587     }
8588     ReplaceElemInGroups( elem, newElem, meshDS);
8589     if( newElem && smDS )
8590       smDS->AddElement( newElem );
8591
8592      // remove central nodes
8593     for ( size_t i = nodes.size() - nbCentralNodes; i < nodes.size(); ++i )
8594       if ( nodes[i]->NbInverseElements() == 0 )
8595         meshDS->RemoveFreeNode( nodes[i], smDS, /*fromGroups=*/true );
8596
8597   } // loop on theElements
8598
8599   if ( !theForce3d )
8600   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8601     // helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8602     // helper.FixQuadraticElements( myError );
8603     SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
8604   }
8605 }
8606
8607 //=======================================================================
8608 /*!
8609  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8610  * \return int - nb of checked elements
8611  */
8612 //=======================================================================
8613
8614 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
8615                                      SMDS_ElemIteratorPtr theItr,
8616                                      const int            theShapeID)
8617 {
8618   int nbElem = 0;
8619   SMESHDS_Mesh* meshDS = GetMeshDS();
8620
8621   while( theItr->more() )
8622   {
8623     const SMDS_MeshElement* elem = theItr->next();
8624     nbElem++;
8625     if( elem && elem->IsQuadratic())
8626     {
8627       int id                    = elem->GetID();
8628       int nbCornerNodes         = elem->NbCornerNodes();
8629       SMDSAbs_ElementType aType = elem->GetType();
8630
8631       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
8632
8633       //remove a quadratic element
8634       if ( !theSm || !theSm->Contains( elem ))
8635         theSm = meshDS->MeshElements( elem->getshapeId() );
8636       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
8637
8638       // remove medium nodes
8639       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
8640         if ( nodes[i]->NbInverseElements() == 0 )
8641           meshDS->RemoveFreeNode( nodes[i], theSm );
8642
8643       // add a linear element
8644       nodes.resize( nbCornerNodes );
8645       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
8646       ReplaceElemInGroups(elem, newElem, meshDS);
8647       if( theSm && newElem )
8648         theSm->AddElement( newElem );
8649     }
8650   }
8651   return nbElem;
8652 }
8653
8654 //=======================================================================
8655 //function : ConvertFromQuadratic
8656 //purpose  :
8657 //=======================================================================
8658
8659 bool SMESH_MeshEditor::ConvertFromQuadratic()
8660 {
8661   int nbCheckedElems = 0;
8662   if ( myMesh->HasShapeToMesh() )
8663   {
8664     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8665     {
8666       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8667       while ( smIt->more() ) {
8668         SMESH_subMesh* sm = smIt->next();
8669         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8670           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8671       }
8672     }
8673   }
8674
8675   int totalNbElems =
8676     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8677   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8678   {
8679     SMESHDS_SubMesh *aSM = 0;
8680     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8681   }
8682
8683   return true;
8684 }
8685
8686 namespace
8687 {
8688   //================================================================================
8689   /*!
8690    * \brief Return true if all medium nodes of the element are in the node set
8691    */
8692   //================================================================================
8693
8694   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
8695   {
8696     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
8697       if ( !nodeSet.count( elem->GetNode(i) ))
8698         return false;
8699     return true;
8700   }
8701 }
8702
8703 //================================================================================
8704 /*!
8705  * \brief Makes given elements linear
8706  */
8707 //================================================================================
8708
8709 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
8710 {
8711   if ( theElements.empty() ) return;
8712
8713   // collect IDs of medium nodes of theElements; some of these nodes will be removed
8714   set<int> mediumNodeIDs;
8715   TIDSortedElemSet::iterator eIt = theElements.begin();
8716   for ( ; eIt != theElements.end(); ++eIt )
8717   {
8718     const SMDS_MeshElement* e = *eIt;
8719     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
8720       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
8721   }
8722
8723   // replace given elements by linear ones
8724   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
8725   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
8726   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
8727
8728   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
8729   // except those elements sharing medium nodes of quadratic element whose medium nodes
8730   // are not all in mediumNodeIDs
8731
8732   // get remaining medium nodes
8733   TIDSortedNodeSet mediumNodes;
8734   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
8735   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
8736     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
8737       mediumNodes.insert( mediumNodes.end(), n );
8738
8739   // find more quadratic elements to convert
8740   TIDSortedElemSet moreElemsToConvert;
8741   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
8742   for ( ; nIt != mediumNodes.end(); ++nIt )
8743   {
8744     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
8745     while ( invIt->more() )
8746     {
8747       const SMDS_MeshElement* e = invIt->next();
8748       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
8749       {
8750         // find a more complex element including e and
8751         // whose medium nodes are not in mediumNodes
8752         bool complexFound = false;
8753         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
8754         {
8755           SMDS_ElemIteratorPtr invIt2 =
8756             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
8757           while ( invIt2->more() )
8758           {
8759             const SMDS_MeshElement* eComplex = invIt2->next();
8760             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
8761             {
8762               int nbCommonNodes = SMESH_MeshAlgos::GetCommonNodes( e, eComplex ).size();
8763               if ( nbCommonNodes == e->NbNodes())
8764               {
8765                 complexFound = true;
8766                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
8767                 break;
8768               }
8769             }
8770           }
8771         }
8772         if ( !complexFound )
8773           moreElemsToConvert.insert( e );
8774       }
8775     }
8776   }
8777   elemIt = SMDS_ElemIteratorPtr
8778     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
8779   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
8780 }
8781
8782 //=======================================================================
8783 //function : SewSideElements
8784 //purpose  :
8785 //=======================================================================
8786
8787 SMESH_MeshEditor::Sew_Error
8788 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
8789                                    TIDSortedElemSet&    theSide2,
8790                                    const SMDS_MeshNode* theFirstNode1,
8791                                    const SMDS_MeshNode* theFirstNode2,
8792                                    const SMDS_MeshNode* theSecondNode1,
8793                                    const SMDS_MeshNode* theSecondNode2)
8794 {
8795   myLastCreatedElems.Clear();
8796   myLastCreatedNodes.Clear();
8797
8798   MESSAGE ("::::SewSideElements()");
8799   if ( theSide1.size() != theSide2.size() )
8800     return SEW_DIFF_NB_OF_ELEMENTS;
8801
8802   Sew_Error aResult = SEW_OK;
8803   // Algo:
8804   // 1. Build set of faces representing each side
8805   // 2. Find which nodes of the side 1 to merge with ones on the side 2
8806   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8807
8808   // =======================================================================
8809   // 1. Build set of faces representing each side:
8810   // =======================================================================
8811   // a. build set of nodes belonging to faces
8812   // b. complete set of faces: find missing faces whose nodes are in set of nodes
8813   // c. create temporary faces representing side of volumes if correspondent
8814   //    face does not exist
8815
8816   SMESHDS_Mesh* aMesh = GetMeshDS();
8817   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
8818   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
8819   TIDSortedElemSet             faceSet1, faceSet2;
8820   set<const SMDS_MeshElement*> volSet1,  volSet2;
8821   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
8822   TIDSortedElemSet             * faceSetPtr[] = { &faceSet1, &faceSet2 };
8823   set<const SMDS_MeshElement*> *  volSetPtr[] = { &volSet1,  &volSet2  };
8824   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
8825   TIDSortedElemSet             * elemSetPtr[] = { &theSide1, &theSide2 };
8826   int iSide, iFace, iNode;
8827
8828   list<const SMDS_MeshElement* > tempFaceList;
8829   for ( iSide = 0; iSide < 2; iSide++ ) {
8830     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
8831     TIDSortedElemSet             * elemSet = elemSetPtr[ iSide ];
8832     TIDSortedElemSet             * faceSet = faceSetPtr[ iSide ];
8833     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
8834     set<const SMDS_MeshElement*>::iterator vIt;
8835     TIDSortedElemSet::iterator eIt;
8836     set<const SMDS_MeshNode*>::iterator    nIt;
8837
8838     // check that given nodes belong to given elements
8839     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
8840     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
8841     int firstIndex = -1, secondIndex = -1;
8842     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8843       const SMDS_MeshElement* elem = *eIt;
8844       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
8845       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
8846       if ( firstIndex > -1 && secondIndex > -1 ) break;
8847     }
8848     if ( firstIndex < 0 || secondIndex < 0 ) {
8849       // we can simply return until temporary faces created
8850       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
8851     }
8852
8853     // -----------------------------------------------------------
8854     // 1a. Collect nodes of existing faces
8855     //     and build set of face nodes in order to detect missing
8856     //     faces corresponding to sides of volumes
8857     // -----------------------------------------------------------
8858
8859     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
8860
8861     // loop on the given element of a side
8862     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8863       //const SMDS_MeshElement* elem = *eIt;
8864       const SMDS_MeshElement* elem = *eIt;
8865       if ( elem->GetType() == SMDSAbs_Face ) {
8866         faceSet->insert( elem );
8867         set <const SMDS_MeshNode*> faceNodeSet;
8868         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
8869         while ( nodeIt->more() ) {
8870           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8871           nodeSet->insert( n );
8872           faceNodeSet.insert( n );
8873         }
8874         setOfFaceNodeSet.insert( faceNodeSet );
8875       }
8876       else if ( elem->GetType() == SMDSAbs_Volume )
8877         volSet->insert( elem );
8878     }
8879     // ------------------------------------------------------------------------------
8880     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
8881     // ------------------------------------------------------------------------------
8882
8883     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8884       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8885       while ( fIt->more() ) { // loop on faces sharing a node
8886         const SMDS_MeshElement* f = fIt->next();
8887         if ( faceSet->find( f ) == faceSet->end() ) {
8888           // check if all nodes are in nodeSet and
8889           // complete setOfFaceNodeSet if they are
8890           set <const SMDS_MeshNode*> faceNodeSet;
8891           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8892           bool allInSet = true;
8893           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8894             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8895             if ( nodeSet->find( n ) == nodeSet->end() )
8896               allInSet = false;
8897             else
8898               faceNodeSet.insert( n );
8899           }
8900           if ( allInSet ) {
8901             faceSet->insert( f );
8902             setOfFaceNodeSet.insert( faceNodeSet );
8903           }
8904         }
8905       }
8906     }
8907
8908     // -------------------------------------------------------------------------
8909     // 1c. Create temporary faces representing sides of volumes if correspondent
8910     //     face does not exist
8911     // -------------------------------------------------------------------------
8912
8913     if ( !volSet->empty() ) {
8914       //int nodeSetSize = nodeSet->size();
8915
8916       // loop on given volumes
8917       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
8918         SMDS_VolumeTool vol (*vIt);
8919         // loop on volume faces: find free faces
8920         // --------------------------------------
8921         list<const SMDS_MeshElement* > freeFaceList;
8922         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
8923           if ( !vol.IsFreeFace( iFace ))
8924             continue;
8925           // check if there is already a face with same nodes in a face set
8926           const SMDS_MeshElement* aFreeFace = 0;
8927           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
8928           int nbNodes = vol.NbFaceNodes( iFace );
8929           set <const SMDS_MeshNode*> faceNodeSet;
8930           vol.GetFaceNodes( iFace, faceNodeSet );
8931           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
8932           if ( isNewFace ) {
8933             // no such a face is given but it still can exist, check it
8934             vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
8935             aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
8936           }
8937           if ( !aFreeFace ) {
8938             // create a temporary face
8939             if ( nbNodes == 3 ) {
8940               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
8941               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
8942             }
8943             else if ( nbNodes == 4 ) {
8944               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8945               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8946             }
8947             else {
8948               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8949               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
8950               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
8951             }
8952             if ( aFreeFace )
8953               tempFaceList.push_back( aFreeFace );
8954           }
8955
8956           if ( aFreeFace )
8957             freeFaceList.push_back( aFreeFace );
8958
8959         } // loop on faces of a volume
8960
8961         // choose one of several free faces of a volume
8962         // --------------------------------------------
8963         if ( freeFaceList.size() > 1 ) {
8964           // choose a face having max nb of nodes shared by other elems of a side
8965           int maxNbNodes = -1;
8966           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
8967           while ( fIt != freeFaceList.end() ) { // loop on free faces
8968             int nbSharedNodes = 0;
8969             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8970             while ( nodeIt->more() ) { // loop on free face nodes
8971               const SMDS_MeshNode* n =
8972                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8973               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
8974               while ( invElemIt->more() ) {
8975                 const SMDS_MeshElement* e = invElemIt->next();
8976                 nbSharedNodes += faceSet->count( e );
8977                 nbSharedNodes += elemSet->count( e );
8978               }
8979             }
8980             if ( nbSharedNodes > maxNbNodes ) {
8981               maxNbNodes = nbSharedNodes;
8982               freeFaceList.erase( freeFaceList.begin(), fIt++ );
8983             }
8984             else if ( nbSharedNodes == maxNbNodes ) {
8985               fIt++;
8986             }
8987             else {
8988               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
8989             }
8990           }
8991           if ( freeFaceList.size() > 1 )
8992           {
8993             // could not choose one face, use another way
8994             // choose a face most close to the bary center of the opposite side
8995             gp_XYZ aBC( 0., 0., 0. );
8996             set <const SMDS_MeshNode*> addedNodes;
8997             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
8998             eIt = elemSet2->begin();
8999             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9000               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9001               while ( nodeIt->more() ) { // loop on free face nodes
9002                 const SMDS_MeshNode* n =
9003                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9004                 if ( addedNodes.insert( n ).second )
9005                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9006               }
9007             }
9008             aBC /= addedNodes.size();
9009             double minDist = DBL_MAX;
9010             fIt = freeFaceList.begin();
9011             while ( fIt != freeFaceList.end() ) { // loop on free faces
9012               double dist = 0;
9013               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9014               while ( nodeIt->more() ) { // loop on free face nodes
9015                 const SMDS_MeshNode* n =
9016                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9017                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9018                 dist += ( aBC - p ).SquareModulus();
9019               }
9020               if ( dist < minDist ) {
9021                 minDist = dist;
9022                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9023               }
9024               else
9025                 fIt = freeFaceList.erase( fIt++ );
9026             }
9027           }
9028         } // choose one of several free faces of a volume
9029
9030         if ( freeFaceList.size() == 1 ) {
9031           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9032           faceSet->insert( aFreeFace );
9033           // complete a node set with nodes of a found free face
9034           //           for ( iNode = 0; iNode < ; iNode++ )
9035           //             nodeSet->insert( fNodes[ iNode ] );
9036         }
9037
9038       } // loop on volumes of a side
9039
9040       //       // complete a set of faces if new nodes in a nodeSet appeared
9041       //       // ----------------------------------------------------------
9042       //       if ( nodeSetSize != nodeSet->size() ) {
9043       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9044       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9045       //           while ( fIt->more() ) { // loop on faces sharing a node
9046       //             const SMDS_MeshElement* f = fIt->next();
9047       //             if ( faceSet->find( f ) == faceSet->end() ) {
9048       //               // check if all nodes are in nodeSet and
9049       //               // complete setOfFaceNodeSet if they are
9050       //               set <const SMDS_MeshNode*> faceNodeSet;
9051       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9052       //               bool allInSet = true;
9053       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9054       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9055       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9056       //                   allInSet = false;
9057       //                 else
9058       //                   faceNodeSet.insert( n );
9059       //               }
9060       //               if ( allInSet ) {
9061       //                 faceSet->insert( f );
9062       //                 setOfFaceNodeSet.insert( faceNodeSet );
9063       //               }
9064       //             }
9065       //           }
9066       //         }
9067       //       }
9068     } // Create temporary faces, if there are volumes given
9069   } // loop on sides
9070
9071   if ( faceSet1.size() != faceSet2.size() ) {
9072     // delete temporary faces: they are in reverseElements of actual nodes
9073 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9074 //    while ( tmpFaceIt->more() )
9075 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9076 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9077 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9078 //      aMesh->RemoveElement(*tmpFaceIt);
9079     MESSAGE("Diff nb of faces");
9080     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9081   }
9082
9083   // ============================================================
9084   // 2. Find nodes to merge:
9085   //              bind a node to remove to a node to put instead
9086   // ============================================================
9087
9088   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9089   if ( theFirstNode1 != theFirstNode2 )
9090     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9091   if ( theSecondNode1 != theSecondNode2 )
9092     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9093
9094   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9095   set< long > linkIdSet; // links to process
9096   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9097
9098   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9099   list< NLink > linkList[2];
9100   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9101   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9102   // loop on links in linkList; find faces by links and append links
9103   // of the found faces to linkList
9104   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9105   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
9106   {
9107     NLink link[] = { *linkIt[0], *linkIt[1] };
9108     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9109     if ( !linkIdSet.count( linkID ) )
9110       continue;
9111
9112     // by links, find faces in the face sets,
9113     // and find indices of link nodes in the found faces;
9114     // in a face set, there is only one or no face sharing a link
9115     // ---------------------------------------------------------------
9116
9117     const SMDS_MeshElement* face[] = { 0, 0 };
9118     vector<const SMDS_MeshNode*> fnodes[2];
9119     int iLinkNode[2][2];
9120     TIDSortedElemSet avoidSet;
9121     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9122       const SMDS_MeshNode* n1 = link[iSide].first;
9123       const SMDS_MeshNode* n2 = link[iSide].second;
9124       //cout << "Side " << iSide << " ";
9125       //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
9126       // find a face by two link nodes
9127       face[ iSide ] = SMESH_MeshAlgos::FindFaceInSet( n1, n2,
9128                                                       *faceSetPtr[ iSide ], avoidSet,
9129                                                       &iLinkNode[iSide][0],
9130                                                       &iLinkNode[iSide][1] );
9131       if ( face[ iSide ])
9132       {
9133         //cout << " F " << face[ iSide]->GetID() <<endl;
9134         faceSetPtr[ iSide ]->erase( face[ iSide ]);
9135         // put face nodes to fnodes
9136         if ( face[ iSide ]->IsQuadratic() )
9137         {
9138           // use interlaced nodes iterator
9139           const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
9140           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9141           SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
9142           while ( nIter->more() )
9143             fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
9144         }
9145         else
9146         {
9147           fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
9148                                   face[ iSide ]->end_nodes() );
9149         }
9150         fnodes[ iSide ].push_back( fnodes[ iSide ].front());
9151       }
9152     }
9153
9154     // check similarity of elements of the sides
9155     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
9156       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9157       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9158         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9159       }
9160       else {
9161         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9162       }
9163       break; // do not return because it's necessary to remove tmp faces
9164     }
9165
9166     // set nodes to merge
9167     // -------------------
9168
9169     if ( face[0] && face[1] )  {
9170       const int nbNodes = face[0]->NbNodes();
9171       if ( nbNodes != face[1]->NbNodes() ) {
9172         MESSAGE("Diff nb of face nodes");
9173         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9174         break; // do not return because it s necessary to remove tmp faces
9175       }
9176       bool reverse[] = { false, false }; // order of nodes in the link
9177       for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9178         // analyse link orientation in faces
9179         int i1 = iLinkNode[ iSide ][ 0 ];
9180         int i2 = iLinkNode[ iSide ][ 1 ];
9181         reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9182       }
9183       int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
9184       int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
9185       for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
9186       {
9187         nReplaceMap.insert  ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
9188                                           fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
9189       }
9190
9191       // add other links of the faces to linkList
9192       // -----------------------------------------
9193
9194       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9195         linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
9196         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9197         if ( !iter_isnew.second ) { // already in a set: no need to process
9198           linkIdSet.erase( iter_isnew.first );
9199         }
9200         else // new in set == encountered for the first time: add
9201         {
9202           const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
9203           const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
9204           linkList[0].push_back ( NLink( n1, n2 ));
9205           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9206         }
9207       }
9208     } // 2 faces found
9209
9210     if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
9211       break;
9212
9213   } // loop on link lists
9214
9215   if ( aResult == SEW_OK &&
9216        ( //linkIt[0] != linkList[0].end() ||
9217          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9218     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9219              " " << (faceSetPtr[1]->empty()));
9220     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9221   }
9222
9223   // ====================================================================
9224   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9225   // ====================================================================
9226
9227   // delete temporary faces
9228 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9229 //  while ( tmpFaceIt->more() )
9230 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9231   list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9232   for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9233     aMesh->RemoveElement(*tmpFaceIt);
9234
9235   if ( aResult != SEW_OK)
9236     return aResult;
9237
9238   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9239   // loop on nodes replacement map
9240   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9241   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9242     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9243       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9244       nodeIDsToRemove.push_back( nToRemove->GetID() );
9245       // loop on elements sharing nToRemove
9246       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9247       while ( invElemIt->more() ) {
9248         const SMDS_MeshElement* e = invElemIt->next();
9249         // get a new suite of nodes: make replacement
9250         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9251         vector< const SMDS_MeshNode*> nodes( nbNodes );
9252         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9253         while ( nIt->more() ) {
9254           const SMDS_MeshNode* n =
9255             static_cast<const SMDS_MeshNode*>( nIt->next() );
9256           nnIt = nReplaceMap.find( n );
9257           if ( nnIt != nReplaceMap.end() ) {
9258             nbReplaced++;
9259             n = (*nnIt).second;
9260           }
9261           nodes[ i++ ] = n;
9262         }
9263         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9264         //         elemIDsToRemove.push_back( e->GetID() );
9265         //       else
9266         if ( nbReplaced )
9267           {
9268             SMDSAbs_ElementType etyp = e->GetType();
9269             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
9270             if (newElem)
9271               {
9272                 myLastCreatedElems.Append(newElem);
9273                 AddToSameGroups(newElem, e, aMesh);
9274                 int aShapeId = e->getshapeId();
9275                 if ( aShapeId )
9276                   {
9277                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
9278                   }
9279               }
9280             aMesh->RemoveElement(e);
9281           }
9282       }
9283     }
9284
9285   Remove( nodeIDsToRemove, true );
9286
9287   return aResult;
9288 }
9289
9290 //================================================================================
9291 /*!
9292  * \brief Find corresponding nodes in two sets of faces
9293  * \param theSide1 - first face set
9294  * \param theSide2 - second first face
9295  * \param theFirstNode1 - a boundary node of set 1
9296  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9297  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9298  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9299  * \param nReplaceMap - output map of corresponding nodes
9300  * \return bool  - is a success or not
9301  */
9302 //================================================================================
9303
9304 #ifdef _DEBUG_
9305 //#define DEBUG_MATCHING_NODES
9306 #endif
9307
9308 SMESH_MeshEditor::Sew_Error
9309 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9310                                     set<const SMDS_MeshElement*>& theSide2,
9311                                     const SMDS_MeshNode*          theFirstNode1,
9312                                     const SMDS_MeshNode*          theFirstNode2,
9313                                     const SMDS_MeshNode*          theSecondNode1,
9314                                     const SMDS_MeshNode*          theSecondNode2,
9315                                     TNodeNodeMap &                nReplaceMap)
9316 {
9317   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9318
9319   nReplaceMap.clear();
9320   if ( theFirstNode1 != theFirstNode2 )
9321     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9322   if ( theSecondNode1 != theSecondNode2 )
9323     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9324
9325   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9326   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9327
9328   list< NLink > linkList[2];
9329   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9330   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9331
9332   // loop on links in linkList; find faces by links and append links
9333   // of the found faces to linkList
9334   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9335   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9336     NLink link[] = { *linkIt[0], *linkIt[1] };
9337     if ( linkSet.find( link[0] ) == linkSet.end() )
9338       continue;
9339
9340     // by links, find faces in the face sets,
9341     // and find indices of link nodes in the found faces;
9342     // in a face set, there is only one or no face sharing a link
9343     // ---------------------------------------------------------------
9344
9345     const SMDS_MeshElement* face[] = { 0, 0 };
9346     list<const SMDS_MeshNode*> notLinkNodes[2];
9347     //bool reverse[] = { false, false }; // order of notLinkNodes
9348     int nbNodes[2];
9349     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9350     {
9351       const SMDS_MeshNode* n1 = link[iSide].first;
9352       const SMDS_MeshNode* n2 = link[iSide].second;
9353       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9354       set< const SMDS_MeshElement* > facesOfNode1;
9355       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9356       {
9357         // during a loop of the first node, we find all faces around n1,
9358         // during a loop of the second node, we find one face sharing both n1 and n2
9359         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9360         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9361         while ( fIt->more() ) { // loop on faces sharing a node
9362           const SMDS_MeshElement* f = fIt->next();
9363           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9364               ! facesOfNode1.insert( f ).second ) // f encounters twice
9365           {
9366             if ( face[ iSide ] ) {
9367               MESSAGE( "2 faces per link " );
9368               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9369             }
9370             face[ iSide ] = f;
9371             faceSet->erase( f );
9372
9373             // get not link nodes
9374             int nbN = f->NbNodes();
9375             if ( f->IsQuadratic() )
9376               nbN /= 2;
9377             nbNodes[ iSide ] = nbN;
9378             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9379             int i1 = f->GetNodeIndex( n1 );
9380             int i2 = f->GetNodeIndex( n2 );
9381             int iEnd = nbN, iBeg = -1, iDelta = 1;
9382             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9383             if ( reverse ) {
9384               std::swap( iEnd, iBeg ); iDelta = -1;
9385             }
9386             int i = i2;
9387             while ( true ) {
9388               i += iDelta;
9389               if ( i == iEnd ) i = iBeg + iDelta;
9390               if ( i == i1 ) break;
9391               nodes.push_back ( f->GetNode( i ) );
9392             }
9393           }
9394         }
9395       }
9396     }
9397     // check similarity of elements of the sides
9398     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9399       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9400       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9401         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9402       }
9403       else {
9404         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9405       }
9406     }
9407
9408     // set nodes to merge
9409     // -------------------
9410
9411     if ( face[0] && face[1] )  {
9412       if ( nbNodes[0] != nbNodes[1] ) {
9413         MESSAGE("Diff nb of face nodes");
9414         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9415       }
9416 #ifdef DEBUG_MATCHING_NODES
9417       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9418                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9419                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9420 #endif
9421       int nbN = nbNodes[0];
9422       {
9423         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9424         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9425         for ( int i = 0 ; i < nbN - 2; ++i ) {
9426 #ifdef DEBUG_MATCHING_NODES
9427           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9428 #endif
9429           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9430         }
9431       }
9432
9433       // add other links of the face 1 to linkList
9434       // -----------------------------------------
9435
9436       const SMDS_MeshElement* f0 = face[0];
9437       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9438       for ( int i = 0; i < nbN; i++ )
9439       {
9440         const SMDS_MeshNode* n2 = f0->GetNode( i );
9441         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9442           linkSet.insert( SMESH_TLink( n1, n2 ));
9443         if ( !iter_isnew.second ) { // already in a set: no need to process
9444           linkSet.erase( iter_isnew.first );
9445         }
9446         else // new in set == encountered for the first time: add
9447         {
9448 #ifdef DEBUG_MATCHING_NODES
9449           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9450                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9451 #endif
9452           linkList[0].push_back ( NLink( n1, n2 ));
9453           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9454         }
9455         n1 = n2;
9456       }
9457     } // 2 faces found
9458   } // loop on link lists
9459
9460   return SEW_OK;
9461 }
9462
9463 //================================================================================
9464 /*!
9465   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9466   \param theElems - the list of elements (edges or faces) to be replicated
9467   The nodes for duplication could be found from these elements
9468   \param theNodesNot - list of nodes to NOT replicate
9469   \param theAffectedElems - the list of elements (cells and edges) to which the
9470   replicated nodes should be associated to.
9471   \return TRUE if operation has been completed successfully, FALSE otherwise
9472 */
9473 //================================================================================
9474
9475 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9476                                     const TIDSortedElemSet& theNodesNot,
9477                                     const TIDSortedElemSet& theAffectedElems )
9478 {
9479   myLastCreatedElems.Clear();
9480   myLastCreatedNodes.Clear();
9481
9482   if ( theElems.size() == 0 )
9483     return false;
9484
9485   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9486   if ( !aMeshDS )
9487     return false;
9488
9489   bool res = false;
9490   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9491   // duplicate elements and nodes
9492   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9493   // replce nodes by duplications
9494   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9495   return res;
9496 }
9497
9498 //================================================================================
9499 /*!
9500   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9501   \param theMeshDS - mesh instance
9502   \param theElems - the elements replicated or modified (nodes should be changed)
9503   \param theNodesNot - nodes to NOT replicate
9504   \param theNodeNodeMap - relation of old node to new created node
9505   \param theIsDoubleElem - flag os to replicate element or modify
9506   \return TRUE if operation has been completed successfully, FALSE otherwise
9507 */
9508 //================================================================================
9509
9510 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
9511                                     const TIDSortedElemSet& theElems,
9512                                     const TIDSortedElemSet& theNodesNot,
9513                                     std::map< const SMDS_MeshNode*,
9514                                     const SMDS_MeshNode* >& theNodeNodeMap,
9515                                     const bool theIsDoubleElem )
9516 {
9517   MESSAGE("doubleNodes");
9518   // iterate on through element and duplicate them (by nodes duplication)
9519   bool res = false;
9520   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9521   for ( ;  elemItr != theElems.end(); ++elemItr )
9522   {
9523     const SMDS_MeshElement* anElem = *elemItr;
9524     if (!anElem)
9525       continue;
9526
9527     bool isDuplicate = false;
9528     // duplicate nodes to duplicate element
9529     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9530     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9531     int ind = 0;
9532     while ( anIter->more() )
9533     {
9534
9535       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9536       SMDS_MeshNode* aNewNode = aCurrNode;
9537       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9538         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9539       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9540       {
9541         // duplicate node
9542         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9543         theNodeNodeMap[ aCurrNode ] = aNewNode;
9544         myLastCreatedNodes.Append( aNewNode );
9545       }
9546       isDuplicate |= (aCurrNode != aNewNode);
9547       newNodes[ ind++ ] = aNewNode;
9548     }
9549     if ( !isDuplicate )
9550       continue;
9551
9552     if ( theIsDoubleElem )
9553       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
9554     else
9555       {
9556       MESSAGE("ChangeElementNodes");
9557       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9558       }
9559     res = true;
9560   }
9561   return res;
9562 }
9563
9564 //================================================================================
9565 /*!
9566   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9567   \param theNodes - identifiers of nodes to be doubled
9568   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
9569          nodes. If list of element identifiers is empty then nodes are doubled but
9570          they not assigned to elements
9571   \return TRUE if operation has been completed successfully, FALSE otherwise
9572 */
9573 //================================================================================
9574
9575 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
9576                                     const std::list< int >& theListOfModifiedElems )
9577 {
9578   MESSAGE("DoubleNodes");
9579   myLastCreatedElems.Clear();
9580   myLastCreatedNodes.Clear();
9581
9582   if ( theListOfNodes.size() == 0 )
9583     return false;
9584
9585   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9586   if ( !aMeshDS )
9587     return false;
9588
9589   // iterate through nodes and duplicate them
9590
9591   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9592
9593   std::list< int >::const_iterator aNodeIter;
9594   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9595   {
9596     int aCurr = *aNodeIter;
9597     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9598     if ( !aNode )
9599       continue;
9600
9601     // duplicate node
9602
9603     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9604     if ( aNewNode )
9605     {
9606       anOldNodeToNewNode[ aNode ] = aNewNode;
9607       myLastCreatedNodes.Append( aNewNode );
9608     }
9609   }
9610
9611   // Create map of new nodes for modified elements
9612
9613   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9614
9615   std::list< int >::const_iterator anElemIter;
9616   for ( anElemIter = theListOfModifiedElems.begin();
9617         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9618   {
9619     int aCurr = *anElemIter;
9620     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9621     if ( !anElem )
9622       continue;
9623
9624     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9625
9626     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9627     int ind = 0;
9628     while ( anIter->more() )
9629     {
9630       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9631       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9632       {
9633         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9634         aNodeArr[ ind++ ] = aNewNode;
9635       }
9636       else
9637         aNodeArr[ ind++ ] = aCurrNode;
9638     }
9639     anElemToNodes[ anElem ] = aNodeArr;
9640   }
9641
9642   // Change nodes of elements
9643
9644   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9645     anElemToNodesIter = anElemToNodes.begin();
9646   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9647   {
9648     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9649     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9650     if ( anElem )
9651       {
9652       MESSAGE("ChangeElementNodes");
9653       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9654       }
9655   }
9656
9657   return true;
9658 }
9659
9660 namespace {
9661
9662   //================================================================================
9663   /*!
9664   \brief Check if element located inside shape
9665   \return TRUE if IN or ON shape, FALSE otherwise
9666   */
9667   //================================================================================
9668
9669   template<class Classifier>
9670   bool isInside(const SMDS_MeshElement* theElem,
9671                 Classifier&             theClassifier,
9672                 const double            theTol)
9673   {
9674     gp_XYZ centerXYZ (0, 0, 0);
9675     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9676     while (aNodeItr->more())
9677       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
9678
9679     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9680     theClassifier.Perform(aPnt, theTol);
9681     TopAbs_State aState = theClassifier.State();
9682     return (aState == TopAbs_IN || aState == TopAbs_ON );
9683   }
9684
9685   //================================================================================
9686   /*!
9687    * \brief Classifier of the 3D point on the TopoDS_Face
9688    *        with interaface suitable for isInside()
9689    */
9690   //================================================================================
9691
9692   struct _FaceClassifier
9693   {
9694     Extrema_ExtPS       _extremum;
9695     BRepAdaptor_Surface _surface;
9696     TopAbs_State        _state;
9697
9698     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9699     {
9700       _extremum.Initialize( _surface,
9701                             _surface.FirstUParameter(), _surface.LastUParameter(),
9702                             _surface.FirstVParameter(), _surface.LastVParameter(),
9703                             _surface.Tolerance(), _surface.Tolerance() );
9704     }
9705     void Perform(const gp_Pnt& aPnt, double theTol)
9706     {
9707       _state = TopAbs_OUT;
9708       _extremum.Perform(aPnt);
9709       if ( _extremum.IsDone() )
9710         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9711 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
9712           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9713 #else
9714           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9715 #endif
9716     }
9717     TopAbs_State State() const
9718     {
9719       return _state;
9720     }
9721   };
9722 }
9723
9724 //================================================================================
9725 /*!
9726   \brief Identify the elements that will be affected by node duplication (actual duplication is not performed.
9727   This method is the first step of DoubleNodeElemGroupsInRegion.
9728   \param theElems - list of groups of elements (edges or faces) to be replicated
9729   \param theNodesNot - list of groups of nodes not to replicated
9730   \param theShape - shape to detect affected elements (element which geometric center
9731          located on or inside shape).
9732          The replicated nodes should be associated to affected elements.
9733   \return groups of affected elements
9734   \sa DoubleNodeElemGroupsInRegion()
9735  */
9736 //================================================================================
9737
9738 bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
9739                                                    const TIDSortedElemSet& theNodesNot,
9740                                                    const TopoDS_Shape&     theShape,
9741                                                    TIDSortedElemSet&       theAffectedElems)
9742 {
9743   if ( theShape.IsNull() )
9744     return false;
9745
9746   const double aTol = Precision::Confusion();
9747   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
9748   auto_ptr<_FaceClassifier>              aFaceClassifier;
9749   if ( theShape.ShapeType() == TopAbs_SOLID )
9750   {
9751     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
9752     bsc3d->PerformInfinitePoint(aTol);
9753   }
9754   else if (theShape.ShapeType() == TopAbs_FACE )
9755   {
9756     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
9757   }
9758
9759   // iterates on indicated elements and get elements by back references from their nodes
9760   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9761   for ( ;  elemItr != theElems.end(); ++elemItr )
9762   {
9763     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
9764     if (!anElem)
9765       continue;
9766
9767     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
9768     while ( nodeItr->more() )
9769     {
9770       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
9771       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
9772         continue;
9773       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
9774       while ( backElemItr->more() )
9775       {
9776         const SMDS_MeshElement* curElem = backElemItr->next();
9777         if ( curElem && theElems.find(curElem) == theElems.end() &&
9778              ( bsc3d.get() ?
9779                isInside( curElem, *bsc3d, aTol ) :
9780                isInside( curElem, *aFaceClassifier, aTol )))
9781           theAffectedElems.insert( curElem );
9782       }
9783     }
9784   }
9785   return true;
9786 }
9787
9788 //================================================================================
9789 /*!
9790   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9791   \param theElems - group of of elements (edges or faces) to be replicated
9792   \param theNodesNot - group of nodes not to replicate
9793   \param theShape - shape to detect affected elements (element which geometric center
9794   located on or inside shape).
9795   The replicated nodes should be associated to affected elements.
9796   \return TRUE if operation has been completed successfully, FALSE otherwise
9797 */
9798 //================================================================================
9799
9800 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
9801                                             const TIDSortedElemSet& theNodesNot,
9802                                             const TopoDS_Shape&     theShape )
9803 {
9804   if ( theShape.IsNull() )
9805     return false;
9806
9807   const double aTol = Precision::Confusion();
9808   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
9809   auto_ptr<_FaceClassifier>              aFaceClassifier;
9810   if ( theShape.ShapeType() == TopAbs_SOLID )
9811   {
9812     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
9813     bsc3d->PerformInfinitePoint(aTol);
9814   }
9815   else if (theShape.ShapeType() == TopAbs_FACE )
9816   {
9817     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
9818   }
9819
9820   // iterates on indicated elements and get elements by back references from their nodes
9821   TIDSortedElemSet anAffected;
9822   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9823   for ( ;  elemItr != theElems.end(); ++elemItr )
9824   {
9825     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
9826     if (!anElem)
9827       continue;
9828
9829     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
9830     while ( nodeItr->more() )
9831     {
9832       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
9833       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
9834         continue;
9835       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
9836       while ( backElemItr->more() )
9837       {
9838         const SMDS_MeshElement* curElem = backElemItr->next();
9839         if ( curElem && theElems.find(curElem) == theElems.end() &&
9840              ( bsc3d.get() ?
9841                isInside( curElem, *bsc3d, aTol ) :
9842                isInside( curElem, *aFaceClassifier, aTol )))
9843           anAffected.insert( curElem );
9844       }
9845     }
9846   }
9847   return DoubleNodes( theElems, theNodesNot, anAffected );
9848 }
9849
9850 /*!
9851  *  \brief compute an oriented angle between two planes defined by four points.
9852  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
9853  *  @param p0 base of the rotation axe
9854  *  @param p1 extremity of the rotation axe
9855  *  @param g1 belongs to the first plane
9856  *  @param g2 belongs to the second plane
9857  */
9858 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
9859 {
9860 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
9861 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
9862 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
9863 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
9864   gp_Vec vref(p0, p1);
9865   gp_Vec v1(p0, g1);
9866   gp_Vec v2(p0, g2);
9867   gp_Vec n1 = vref.Crossed(v1);
9868   gp_Vec n2 = vref.Crossed(v2);
9869   return n2.AngleWithRef(n1, vref);
9870 }
9871
9872 /*!
9873  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
9874  *  The list of groups must contain at least two groups. The groups have to be disjoint: no common element into two different groups.
9875  * The nodes of the internal faces at the boundaries of the groups are doubled. Optionally, the internal faces are replaced by flat elements.
9876  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
9877  * The flat elements are stored in groups of volumes. These groups are named according to the position of the group in the list:
9878  * 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.
9879  * 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.
9880  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
9881  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
9882  * @param theElems - list of groups of volumes, where a group of volume is a set of
9883  * SMDS_MeshElements sorted by Id.
9884  * @param createJointElems - if TRUE, create the elements
9885  * @return TRUE if operation has been completed successfully, FALSE otherwise
9886  */
9887 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
9888                                                      bool createJointElems)
9889 {
9890   MESSAGE("----------------------------------------------");
9891   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
9892   MESSAGE("----------------------------------------------");
9893
9894   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
9895   meshDS->BuildDownWardConnectivity(true);
9896   CHRONO(50);
9897   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
9898
9899   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
9900   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
9901   //     build the list of nodes shared by 2 or more domains, with their domain indexes
9902
9903   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
9904   std::map<int,int>celldom; // cell vtkId --> domain
9905   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
9906   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
9907   faceDomains.clear();
9908   celldom.clear();
9909   cellDomains.clear();
9910   nodeDomains.clear();
9911   std::map<int,int> emptyMap;
9912   std::set<int> emptySet;
9913   emptyMap.clear();
9914
9915   MESSAGE(".. Number of domains :"<<theElems.size());
9916
9917   // Check if the domains do not share an element
9918   for (int idom = 0; idom < theElems.size()-1; idom++)
9919     {
9920 //       MESSAGE("... Check of domain #" << idom);
9921       const TIDSortedElemSet& domain = theElems[idom];
9922       TIDSortedElemSet::const_iterator elemItr = domain.begin();
9923       for (; elemItr != domain.end(); ++elemItr)
9924         {
9925           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
9926           int idombisdeb = idom + 1 ;
9927           for (int idombis = idombisdeb; idombis < theElems.size(); idombis++) // check if the element belongs to a domain further in the list
9928           {
9929             const TIDSortedElemSet& domainbis = theElems[idombis];
9930             if ( domainbis.count(anElem) )
9931             {
9932               MESSAGE(".... Domain #" << idom);
9933               MESSAGE(".... Domain #" << idombis);
9934               throw SALOME_Exception("The domains are not disjoint.");
9935               return false ;
9936             }
9937           }
9938         }
9939     }
9940
9941   for (int idom = 0; idom < theElems.size(); idom++)
9942     {
9943
9944       // --- build a map (face to duplicate --> volume to modify)
9945       //     with all the faces shared by 2 domains (group of elements)
9946       //     and corresponding volume of this domain, for each shared face.
9947       //     a volume has a face shared by 2 domains if it has a neighbor which is not in his domain.
9948
9949       MESSAGE("... Neighbors of domain #" << idom);
9950       const TIDSortedElemSet& domain = theElems[idom];
9951       TIDSortedElemSet::const_iterator elemItr = domain.begin();
9952       for (; elemItr != domain.end(); ++elemItr)
9953         {
9954           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
9955           if (!anElem)
9956             continue;
9957           int vtkId = anElem->getVtkId();
9958           //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
9959           int neighborsVtkIds[NBMAXNEIGHBORS];
9960           int downIds[NBMAXNEIGHBORS];
9961           unsigned char downTypes[NBMAXNEIGHBORS];
9962           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
9963           for (int n = 0; n < nbNeighbors; n++)
9964             {
9965               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
9966               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
9967               if (! domain.count(elem)) // neighbor is in another domain : face is shared
9968                 {
9969                   bool ok = false ;
9970                   for (int idombis = 0; idombis < theElems.size(); idombis++) // check if the neighbor belongs to another domain of the list
9971                   {
9972                     // MESSAGE("Domain " << idombis);
9973                     const TIDSortedElemSet& domainbis = theElems[idombis];
9974                     if ( domainbis.count(elem)) ok = true ; // neighbor is in a correct domain : face is kept
9975                   }
9976                   if ( ok ) // the characteristics of the face is stored
9977                   {
9978                     DownIdType face(downIds[n], downTypes[n]);
9979                     if (!faceDomains.count(face))
9980                       faceDomains[face] = emptyMap; // create an empty entry for face
9981                     if (!faceDomains[face].count(idom))
9982                       {
9983                         faceDomains[face][idom] = vtkId; // volume associated to face in this domain
9984                         celldom[vtkId] = idom;
9985                         //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
9986                       }
9987                   }
9988                 }
9989             }
9990         }
9991     }
9992
9993   //MESSAGE("Number of shared faces " << faceDomains.size());
9994   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
9995
9996   // --- explore the shared faces domain by domain,
9997   //     explore the nodes of the face and see if they belong to a cell in the domain,
9998   //     which has only a node or an edge on the border (not a shared face)
9999
10000   for (int idomain = 0; idomain < theElems.size(); idomain++)
10001     {
10002       //MESSAGE("Domain " << idomain);
10003       const TIDSortedElemSet& domain = theElems[idomain];
10004       itface = faceDomains.begin();
10005       for (; itface != faceDomains.end(); ++itface)
10006         {
10007           std::map<int, int> domvol = itface->second;
10008           if (!domvol.count(idomain))
10009             continue;
10010           DownIdType face = itface->first;
10011           //MESSAGE(" --- face " << face.cellId);
10012           std::set<int> oldNodes;
10013           oldNodes.clear();
10014           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10015           std::set<int>::iterator itn = oldNodes.begin();
10016           for (; itn != oldNodes.end(); ++itn)
10017             {
10018               int oldId = *itn;
10019               //MESSAGE("     node " << oldId);
10020               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10021               for (int i=0; i<l.ncells; i++)
10022                 {
10023                   int vtkId = l.cells[i];
10024                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10025                   if (!domain.count(anElem))
10026                     continue;
10027                   int vtkType = grid->GetCellType(vtkId);
10028                   int downId = grid->CellIdToDownId(vtkId);
10029                   if (downId < 0)
10030                     {
10031                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
10032                       continue; // not OK at this stage of the algorithm:
10033                                 //no cells created after BuildDownWardConnectivity
10034                     }
10035                   DownIdType aCell(downId, vtkType);
10036                   if (!cellDomains.count(aCell))
10037                     cellDomains[aCell] = emptyMap; // create an empty entry for cell
10038                   cellDomains[aCell][idomain] = vtkId;
10039                   celldom[vtkId] = idomain;
10040                   //MESSAGE("       cell " << vtkId << " domain " << idomain);
10041                 }
10042             }
10043         }
10044     }
10045
10046   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10047   //     for each shared face, get the nodes
10048   //     for each node, for each domain of the face, create a clone of the node
10049
10050   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10051   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10052   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
10053
10054   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10055   std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
10056   std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
10057
10058   MESSAGE(".. Duplication of the nodes");
10059   for (int idomain = 0; idomain < theElems.size(); idomain++)
10060     {
10061       itface = faceDomains.begin();
10062       for (; itface != faceDomains.end(); ++itface)
10063         {
10064           std::map<int, int> domvol = itface->second;
10065           if (!domvol.count(idomain))
10066             continue;
10067           DownIdType face = itface->first;
10068           //MESSAGE(" --- face " << face.cellId);
10069           std::set<int> oldNodes;
10070           oldNodes.clear();
10071           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10072           std::set<int>::iterator itn = oldNodes.begin();
10073           for (; itn != oldNodes.end(); ++itn)
10074             {
10075               int oldId = *itn;
10076               //MESSAGE("-+-+-a node " << oldId);
10077               if (!nodeDomains.count(oldId))
10078                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10079               if (nodeDomains[oldId].empty())
10080                 {
10081                   nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
10082                   //MESSAGE("-+-+-b     oldNode " << oldId << " domain " << idomain);
10083                 }
10084               std::map<int, int>::iterator itdom = domvol.begin();
10085               for (; itdom != domvol.end(); ++itdom)
10086                 {
10087                   int idom = itdom->first;
10088                   //MESSAGE("         domain " << idom);
10089                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
10090                     {
10091                       if (nodeDomains[oldId].size() >= 2) // a multiple node
10092                         {
10093                           vector<int> orderedDoms;
10094                           //MESSAGE("multiple node " << oldId);
10095                           if (mutipleNodes.count(oldId))
10096                             orderedDoms = mutipleNodes[oldId];
10097                           else
10098                             {
10099                               map<int,int>::iterator it = nodeDomains[oldId].begin();
10100                               for (; it != nodeDomains[oldId].end(); ++it)
10101                                 orderedDoms.push_back(it->first);
10102                             }
10103                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
10104                           //stringstream txt;
10105                           //for (int i=0; i<orderedDoms.size(); i++)
10106                           //  txt << orderedDoms[i] << " ";
10107                           //MESSAGE("orderedDoms " << txt.str());
10108                           mutipleNodes[oldId] = orderedDoms;
10109                         }
10110                       double *coords = grid->GetPoint(oldId);
10111                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10112                       int newId = newNode->getVtkId();
10113                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
10114                       //MESSAGE("-+-+-c     oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
10115                     }
10116                 }
10117             }
10118         }
10119     }
10120
10121   MESSAGE(".. Creation of elements");
10122   for (int idomain = 0; idomain < theElems.size(); idomain++)
10123     {
10124       itface = faceDomains.begin();
10125       for (; itface != faceDomains.end(); ++itface)
10126         {
10127           std::map<int, int> domvol = itface->second;
10128           if (!domvol.count(idomain))
10129             continue;
10130           DownIdType face = itface->first;
10131           //MESSAGE(" --- face " << face.cellId);
10132           std::set<int> oldNodes;
10133           oldNodes.clear();
10134           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10135           int nbMultipleNodes = 0;
10136           std::set<int>::iterator itn = oldNodes.begin();
10137           for (; itn != oldNodes.end(); ++itn)
10138             {
10139               int oldId = *itn;
10140               if (mutipleNodes.count(oldId))
10141                 nbMultipleNodes++;
10142             }
10143           if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains
10144             {
10145               //MESSAGE("multiple Nodes detected on a shared face");
10146               int downId = itface->first.cellId;
10147               unsigned char cellType = itface->first.cellType;
10148               // --- shared edge or shared face ?
10149               if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
10150                 {
10151                   int nodes[3];
10152                   int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
10153                   for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
10154                     if (mutipleNodes.count(nodes[i]))
10155                       if (!mutipleNodesToFace.count(nodes[i]))
10156                         mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
10157                 }
10158               else // shared face (between two volumes)
10159                 {
10160                   int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
10161                   const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
10162                   const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
10163                   for (int ie =0; ie < nbEdges; ie++)
10164                     {
10165                       int nodes[3];
10166                       int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
10167                       if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
10168                         {
10169                           vector<int> vn0 = mutipleNodes[nodes[0]];
10170                           vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
10171                           vector<int> doms;
10172                           for (int i0 = 0; i0 < vn0.size(); i0++)
10173                             for (int i1 = 0; i1 < vn1.size(); i1++)
10174                               if (vn0[i0] == vn1[i1])
10175                                 doms.push_back(vn0[i0]);
10176                           if (doms.size() >2)
10177                             {
10178                               //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
10179                               double *coords = grid->GetPoint(nodes[0]);
10180                               gp_Pnt p0(coords[0], coords[1], coords[2]);
10181                               coords = grid->GetPoint(nodes[nbNodes - 1]);
10182                               gp_Pnt p1(coords[0], coords[1], coords[2]);
10183                               gp_Pnt gref;
10184                               int vtkVolIds[1000];  // an edge can belong to a lot of volumes
10185                               map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
10186                               map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
10187                               int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
10188                               for (int id=0; id < doms.size(); id++)
10189                                 {
10190                                   int idom = doms[id];
10191                                   for (int ivol=0; ivol<nbvol; ivol++)
10192                                     {
10193                                       int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
10194                                       SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
10195                                       if (theElems[idom].count(elem))
10196                                         {
10197                                           SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
10198                                           domvol[idom] = svol;
10199                                           //MESSAGE("  domain " << idom << " volume " << elem->GetID());
10200                                           double values[3];
10201                                           vtkIdType npts = 0;
10202                                           vtkIdType* pts = 0;
10203                                           grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
10204                                           SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
10205                                           if (id ==0)
10206                                             {
10207                                               gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
10208                                               angleDom[idom] = 0;
10209                                             }
10210                                           else
10211                                             {
10212                                               gp_Pnt g(values[0], values[1], values[2]);
10213                                               angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
10214                                               //MESSAGE("  angle=" << angleDom[idom]);
10215                                             }
10216                                           break;
10217                                         }
10218                                     }
10219                                 }
10220                               map<double, int> sortedDom; // sort domains by angle
10221                               for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
10222                                 sortedDom[ia->second] = ia->first;
10223                               vector<int> vnodes;
10224                               vector<int> vdom;
10225                               for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
10226                                 {
10227                                   vdom.push_back(ib->second);
10228                                   //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
10229                                 }
10230                               for (int ino = 0; ino < nbNodes; ino++)
10231                                 vnodes.push_back(nodes[ino]);
10232                               edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
10233                             }
10234                         }
10235                     }
10236                 }
10237             }
10238         }
10239     }
10240
10241   // --- iterate on shared faces (volumes to modify, face to extrude)
10242   //     get node id's of the face (id SMDS = id VTK)
10243   //     create flat element with old and new nodes if requested
10244
10245   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
10246   //     (domain1 X domain2) = domain1 + MAXINT*domain2
10247
10248   std::map<int, std::map<long,int> > nodeQuadDomains;
10249   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10250
10251   MESSAGE(".. Creation of elements: simple junction");
10252   if (createJointElems)
10253     {
10254       int idg;
10255       string joints2DName = "joints2D";
10256       mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg);
10257       SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
10258       string joints3DName = "joints3D";
10259       mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg);
10260       SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
10261
10262       itface = faceDomains.begin();
10263       for (; itface != faceDomains.end(); ++itface)
10264         {
10265           DownIdType face = itface->first;
10266           std::set<int> oldNodes;
10267           std::set<int>::iterator itn;
10268           oldNodes.clear();
10269           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10270
10271           std::map<int, int> domvol = itface->second;
10272           std::map<int, int>::iterator itdom = domvol.begin();
10273           int dom1 = itdom->first;
10274           int vtkVolId = itdom->second;
10275           itdom++;
10276           int dom2 = itdom->first;
10277           SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
10278                                                              nodeQuadDomains);
10279           stringstream grpname;
10280           grpname << "j_";
10281           if (dom1 < dom2)
10282             grpname << dom1 << "_" << dom2;
10283           else
10284             grpname << dom2 << "_" << dom1;
10285           string namegrp = grpname.str();
10286           if (!mapOfJunctionGroups.count(namegrp))
10287             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
10288           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10289           if (sgrp)
10290             sgrp->Add(vol->GetID());
10291           if (vol->GetType() == SMDSAbs_Volume)
10292             joints3DGrp->Add(vol->GetID());
10293           else if (vol->GetType() == SMDSAbs_Face)
10294             joints2DGrp->Add(vol->GetID());
10295         }
10296     }
10297
10298   // --- create volumes on multiple domain intersection if requested
10299   //     iterate on mutipleNodesToFace
10300   //     iterate on edgesMultiDomains
10301
10302   MESSAGE(".. Creation of elements: multiple junction");
10303   if (createJointElems)
10304     {
10305       // --- iterate on mutipleNodesToFace
10306
10307       std::map<int, std::vector<int> >::iterator itn =  mutipleNodesToFace.begin();
10308       for (; itn != mutipleNodesToFace.end(); ++itn)
10309         {
10310           int node = itn->first;
10311           vector<int> orderDom = itn->second;
10312           vector<vtkIdType> orderedNodes;
10313           for (int idom = 0; idom <orderDom.size(); idom++)
10314             orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
10315             SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
10316
10317             stringstream grpname;
10318             grpname << "m2j_";
10319             grpname << 0 << "_" << 0;
10320             int idg;
10321             string namegrp = grpname.str();
10322             if (!mapOfJunctionGroups.count(namegrp))
10323               mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
10324             SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10325             if (sgrp)
10326               sgrp->Add(face->GetID());
10327         }
10328
10329       // --- iterate on edgesMultiDomains
10330
10331       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
10332       for (; ite != edgesMultiDomains.end(); ++ite)
10333         {
10334           vector<int> nodes = ite->first;
10335           vector<int> orderDom = ite->second;
10336           vector<vtkIdType> orderedNodes;
10337           if (nodes.size() == 2)
10338             {
10339               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
10340               for (int ino=0; ino < nodes.size(); ino++)
10341                 if (orderDom.size() == 3)
10342                   for (int idom = 0; idom <orderDom.size(); idom++)
10343                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
10344                 else
10345                   for (int idom = orderDom.size()-1; idom >=0; idom--)
10346                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
10347               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
10348
10349               int idg;
10350               string namegrp = "jointsMultiples";
10351               if (!mapOfJunctionGroups.count(namegrp))
10352                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
10353               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10354               if (sgrp)
10355                 sgrp->Add(vol->GetID());
10356             }
10357           else
10358             {
10359               INFOS("Quadratic multiple joints not implemented");
10360               // TODO quadratic nodes
10361             }
10362         }
10363     }
10364
10365   // --- list the explicit faces and edges of the mesh that need to be modified,
10366   //     i.e. faces and edges built with one or more duplicated nodes.
10367   //     associate these faces or edges to their corresponding domain.
10368   //     only the first domain found is kept when a face or edge is shared
10369
10370   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
10371   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
10372   faceOrEdgeDom.clear();
10373   feDom.clear();
10374
10375   MESSAGE(".. Modification of elements");
10376   for (int idomain = 0; idomain < theElems.size(); idomain++)
10377     {
10378       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
10379       for (; itnod != nodeDomains.end(); ++itnod)
10380         {
10381           int oldId = itnod->first;
10382           //MESSAGE("     node " << oldId);
10383           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10384           for (int i = 0; i < l.ncells; i++)
10385             {
10386               int vtkId = l.cells[i];
10387               int vtkType = grid->GetCellType(vtkId);
10388               int downId = grid->CellIdToDownId(vtkId);
10389               if (downId < 0)
10390                 continue; // new cells: not to be modified
10391               DownIdType aCell(downId, vtkType);
10392               int volParents[1000];
10393               int nbvol = grid->GetParentVolumes(volParents, vtkId);
10394               for (int j = 0; j < nbvol; j++)
10395                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
10396                   if (!feDom.count(vtkId))
10397                     {
10398                       feDom[vtkId] = idomain;
10399                       faceOrEdgeDom[aCell] = emptyMap;
10400                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
10401                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
10402                       //        << " type " << vtkType << " downId " << downId);
10403                     }
10404             }
10405         }
10406     }
10407
10408   // --- iterate on shared faces (volumes to modify, face to extrude)
10409   //     get node id's of the face
10410   //     replace old nodes by new nodes in volumes, and update inverse connectivity
10411
10412   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
10413   for (int m=0; m<3; m++)
10414     {
10415       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
10416       itface = (*amap).begin();
10417       for (; itface != (*amap).end(); ++itface)
10418         {
10419           DownIdType face = itface->first;
10420           std::set<int> oldNodes;
10421           std::set<int>::iterator itn;
10422           oldNodes.clear();
10423           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10424           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
10425           std::map<int, int> localClonedNodeIds;
10426
10427           std::map<int, int> domvol = itface->second;
10428           std::map<int, int>::iterator itdom = domvol.begin();
10429           for (; itdom != domvol.end(); ++itdom)
10430             {
10431               int idom = itdom->first;
10432               int vtkVolId = itdom->second;
10433               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
10434               localClonedNodeIds.clear();
10435               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10436                 {
10437                   int oldId = *itn;
10438                   if (nodeDomains[oldId].count(idom))
10439                     {
10440                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10441                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
10442                     }
10443                 }
10444               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10445             }
10446         }
10447     }
10448
10449   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
10450   grid->BuildLinks();
10451
10452   CHRONOSTOP(50);
10453   counters::stats();
10454   return true;
10455 }
10456
10457 /*!
10458  * \brief Double nodes on some external faces and create flat elements.
10459  * Flat elements are mainly used by some types of mechanic calculations.
10460  *
10461  * Each group of the list must be constituted of faces.
10462  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10463  * @param theElems - list of groups of faces, where a group of faces is a set of
10464  * SMDS_MeshElements sorted by Id.
10465  * @return TRUE if operation has been completed successfully, FALSE otherwise
10466  */
10467 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
10468 {
10469   MESSAGE("-------------------------------------------------");
10470   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
10471   MESSAGE("-------------------------------------------------");
10472
10473   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10474
10475   // --- For each group of faces
10476   //     duplicate the nodes, create a flat element based on the face
10477   //     replace the nodes of the faces by their clones
10478
10479   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
10480   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
10481   clonedNodes.clear();
10482   intermediateNodes.clear();
10483   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10484   mapOfJunctionGroups.clear();
10485
10486   for (int idom = 0; idom < theElems.size(); idom++)
10487     {
10488       const TIDSortedElemSet& domain = theElems[idom];
10489       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10490       for (; elemItr != domain.end(); ++elemItr)
10491         {
10492           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10493           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
10494           if (!aFace)
10495             continue;
10496           // MESSAGE("aFace=" << aFace->GetID());
10497           bool isQuad = aFace->IsQuadratic();
10498           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
10499
10500           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
10501
10502           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
10503           while (nodeIt->more())
10504             {
10505               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
10506               bool isMedium = isQuad && (aFace->IsMediumNode(node));
10507               if (isMedium)
10508                 ln2.push_back(node);
10509               else
10510                 ln0.push_back(node);
10511
10512               const SMDS_MeshNode* clone = 0;
10513               if (!clonedNodes.count(node))
10514                 {
10515                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
10516                   clonedNodes[node] = clone;
10517                 }
10518               else
10519                 clone = clonedNodes[node];
10520
10521               if (isMedium)
10522                 ln3.push_back(clone);
10523               else
10524                 ln1.push_back(clone);
10525
10526               const SMDS_MeshNode* inter = 0;
10527               if (isQuad && (!isMedium))
10528                 {
10529                   if (!intermediateNodes.count(node))
10530                     {
10531                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
10532                       intermediateNodes[node] = inter;
10533                     }
10534                   else
10535                     inter = intermediateNodes[node];
10536                   ln4.push_back(inter);
10537                 }
10538             }
10539
10540           // --- extrude the face
10541
10542           vector<const SMDS_MeshNode*> ln;
10543           SMDS_MeshVolume* vol = 0;
10544           vtkIdType aType = aFace->GetVtkType();
10545           switch (aType)
10546           {
10547             case VTK_TRIANGLE:
10548               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
10549               // MESSAGE("vol prism " << vol->GetID());
10550               ln.push_back(ln1[0]);
10551               ln.push_back(ln1[1]);
10552               ln.push_back(ln1[2]);
10553               break;
10554             case VTK_QUAD:
10555               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
10556               // MESSAGE("vol hexa " << vol->GetID());
10557               ln.push_back(ln1[0]);
10558               ln.push_back(ln1[1]);
10559               ln.push_back(ln1[2]);
10560               ln.push_back(ln1[3]);
10561               break;
10562             case VTK_QUADRATIC_TRIANGLE:
10563               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
10564                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
10565               // MESSAGE("vol quad prism " << vol->GetID());
10566               ln.push_back(ln1[0]);
10567               ln.push_back(ln1[1]);
10568               ln.push_back(ln1[2]);
10569               ln.push_back(ln3[0]);
10570               ln.push_back(ln3[1]);
10571               ln.push_back(ln3[2]);
10572               break;
10573             case VTK_QUADRATIC_QUAD:
10574 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
10575 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
10576 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
10577               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
10578                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
10579                                       ln4[0], ln4[1], ln4[2], ln4[3]);
10580               // MESSAGE("vol quad hexa " << vol->GetID());
10581               ln.push_back(ln1[0]);
10582               ln.push_back(ln1[1]);
10583               ln.push_back(ln1[2]);
10584               ln.push_back(ln1[3]);
10585               ln.push_back(ln3[0]);
10586               ln.push_back(ln3[1]);
10587               ln.push_back(ln3[2]);
10588               ln.push_back(ln3[3]);
10589               break;
10590             case VTK_POLYGON:
10591               break;
10592             default:
10593               break;
10594           }
10595
10596           if (vol)
10597             {
10598               stringstream grpname;
10599               grpname << "jf_";
10600               grpname << idom;
10601               int idg;
10602               string namegrp = grpname.str();
10603               if (!mapOfJunctionGroups.count(namegrp))
10604                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
10605               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10606               if (sgrp)
10607                 sgrp->Add(vol->GetID());
10608             }
10609
10610           // --- modify the face
10611
10612           aFace->ChangeNodes(&ln[0], ln.size());
10613         }
10614     }
10615   return true;
10616 }
10617
10618 /*!
10619  *  \brief identify all the elements around a geom shape, get the faces delimiting the hole
10620  *  Build groups of volume to remove, groups of faces to replace on the skin of the object,
10621  *  groups of faces to remove inside the object, (idem edges).
10622  *  Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape)
10623  */
10624 void SMESH_MeshEditor::CreateHoleSkin(double radius,
10625                                       const TopoDS_Shape& theShape,
10626                                       SMESH_NodeSearcher* theNodeSearcher,
10627                                       const char* groupName,
10628                                       std::vector<double>&   nodesCoords,
10629                                       std::vector<std::vector<int> >& listOfListOfNodes)
10630 {
10631   MESSAGE("--------------------------------");
10632   MESSAGE("SMESH_MeshEditor::CreateHoleSkin");
10633   MESSAGE("--------------------------------");
10634
10635   // --- zone of volumes to remove is given :
10636   //     1 either by a geom shape (one or more vertices) and a radius,
10637   //     2 either by a group of nodes (representative of the shape)to use with the radius,
10638   //     3 either by a group of nodes where all the elements build on one of this nodes are to remove,
10639   //     In the case 2, the group of nodes is an external group of nodes from another mesh,
10640   //     In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter),
10641   //     defined by it's name.
10642
10643   SMESHDS_GroupBase* groupDS = 0;
10644   SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups();
10645   while ( groupIt->more() )
10646     {
10647       groupDS = 0;
10648       SMESH_Group * group = groupIt->next();
10649       if ( !group ) continue;
10650       groupDS = group->GetGroupDS();
10651       if ( !groupDS || groupDS->IsEmpty() ) continue;
10652       std::string grpName = group->GetName();
10653       //MESSAGE("grpName=" << grpName);
10654       if (grpName == groupName)
10655         break;
10656       else
10657         groupDS = 0;
10658     }
10659
10660   bool isNodeGroup = false;
10661   bool isNodeCoords = false;
10662   if (groupDS)
10663     {
10664       if (groupDS->GetType() != SMDSAbs_Node)
10665         return;
10666       isNodeGroup = true;     // a group of nodes exists and it is in this mesh
10667     }
10668
10669   if (nodesCoords.size() > 0)
10670     isNodeCoords = true; // a list o nodes given by their coordinates
10671   //MESSAGE("---" << isNodeGroup << " " << isNodeCoords);
10672
10673   // --- define groups to build
10674
10675   int idg; // --- group of SMDS volumes
10676   string grpvName = groupName;
10677   grpvName += "_vol";
10678   SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
10679   if (!grp)
10680     {
10681       MESSAGE("group not created " << grpvName);
10682       return;
10683     }
10684   SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
10685
10686   int idgs; // --- group of SMDS faces on the skin
10687   string grpsName = groupName;
10688   grpsName += "_skin";
10689   SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
10690   if (!grps)
10691     {
10692       MESSAGE("group not created " << grpsName);
10693       return;
10694     }
10695   SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
10696
10697   int idgi; // --- group of SMDS faces internal (several shapes)
10698   string grpiName = groupName;
10699   grpiName += "_internalFaces";
10700   SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
10701   if (!grpi)
10702     {
10703       MESSAGE("group not created " << grpiName);
10704       return;
10705     }
10706   SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
10707
10708   int idgei; // --- group of SMDS faces internal (several shapes)
10709   string grpeiName = groupName;
10710   grpeiName += "_internalEdges";
10711   SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
10712   if (!grpei)
10713     {
10714       MESSAGE("group not created " << grpeiName);
10715       return;
10716     }
10717   SMESHDS_Group *sgrpei = dynamic_cast<SMESHDS_Group*>(grpei->GetGroupDS());
10718
10719   // --- build downward connectivity
10720
10721   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10722   meshDS->BuildDownWardConnectivity(true);
10723   SMDS_UnstructuredGrid* grid = meshDS->getGrid();
10724
10725   // --- set of volumes detected inside
10726
10727   std::set<int> setOfInsideVol;
10728   std::set<int> setOfVolToCheck;
10729
10730   std::vector<gp_Pnt> gpnts;
10731   gpnts.clear();
10732
10733   if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
10734     {
10735       MESSAGE("group of nodes provided");
10736       SMDS_ElemIteratorPtr elemIt = groupDS->GetElements();
10737       while ( elemIt->more() )
10738         {
10739           const SMDS_MeshElement* elem = elemIt->next();
10740           if (!elem)
10741             continue;
10742           const SMDS_MeshNode* node = dynamic_cast<const SMDS_MeshNode*>(elem);
10743           if (!node)
10744             continue;
10745           SMDS_MeshElement* vol = 0;
10746           SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume);
10747           while (volItr->more())
10748             {
10749               vol = (SMDS_MeshElement*)volItr->next();
10750               setOfInsideVol.insert(vol->getVtkId());
10751               sgrp->Add(vol->GetID());
10752             }
10753         }
10754     }
10755   else if (isNodeCoords)
10756     {
10757       MESSAGE("list of nodes coordinates provided");
10758       int i = 0;
10759       int k = 0;
10760       while (i < nodesCoords.size()-2)
10761         {
10762           double x = nodesCoords[i++];
10763           double y = nodesCoords[i++];
10764           double z = nodesCoords[i++];
10765           gp_Pnt p = gp_Pnt(x, y ,z);
10766           gpnts.push_back(p);
10767           MESSAGE("TopoDS_Vertex " << k++ << " " << p.X() << " " << p.Y() << " " << p.Z());
10768         }
10769     }
10770   else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius
10771     {
10772       MESSAGE("no group of nodes provided, using vertices from geom shape, and radius");
10773       TopTools_IndexedMapOfShape vertexMap;
10774       TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap );
10775       gp_Pnt p = gp_Pnt(0,0,0);
10776       if (vertexMap.Extent() < 1)
10777         return;
10778
10779       for ( int i = 1; i <= vertexMap.Extent(); ++i )
10780         {
10781           const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i ));
10782           p = BRep_Tool::Pnt(vertex);
10783           gpnts.push_back(p);
10784           MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z());
10785         }
10786     }
10787
10788   if (gpnts.size() > 0)
10789     {
10790       int nodeId = 0;
10791       const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
10792       if (startNode)
10793         nodeId = startNode->GetID();
10794       MESSAGE("nodeId " << nodeId);
10795
10796       double radius2 = radius*radius;
10797       MESSAGE("radius2 " << radius2);
10798
10799       // --- volumes on start node
10800
10801       setOfVolToCheck.clear();
10802       SMDS_MeshElement* startVol = 0;
10803       SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
10804       while (volItr->more())
10805         {
10806           startVol = (SMDS_MeshElement*)volItr->next();
10807           setOfVolToCheck.insert(startVol->getVtkId());
10808         }
10809       if (setOfVolToCheck.empty())
10810         {
10811           MESSAGE("No volumes found");
10812           return;
10813         }
10814
10815       // --- starting with central volumes then their neighbors, check if they are inside
10816       //     or outside the domain, until no more new neighbor volume is inside.
10817       //     Fill the group of inside volumes
10818
10819       std::map<int, double> mapOfNodeDistance2;
10820       mapOfNodeDistance2.clear();
10821       std::set<int> setOfOutsideVol;
10822       while (!setOfVolToCheck.empty())
10823         {
10824           std::set<int>::iterator it = setOfVolToCheck.begin();
10825           int vtkId = *it;
10826           MESSAGE("volume to check,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
10827           bool volInside = false;
10828           vtkIdType npts = 0;
10829           vtkIdType* pts = 0;
10830           grid->GetCellPoints(vtkId, npts, pts);
10831           for (int i=0; i<npts; i++)
10832             {
10833               double distance2 = 0;
10834               if (mapOfNodeDistance2.count(pts[i]))
10835                 {
10836                   distance2 = mapOfNodeDistance2[pts[i]];
10837                   MESSAGE("point " << pts[i] << " distance2 " << distance2);
10838                 }
10839               else
10840                 {
10841                   double *coords = grid->GetPoint(pts[i]);
10842                   gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
10843                   distance2 = 1.E40;
10844                   for (int j=0; j<gpnts.size(); j++)
10845                     {
10846                       double d2 = aPoint.SquareDistance(gpnts[j]);
10847                       if (d2 < distance2)
10848                         {
10849                           distance2 = d2;
10850                           if (distance2 < radius2)
10851                             break;
10852                         }
10853                     }
10854                   mapOfNodeDistance2[pts[i]] = distance2;
10855                   MESSAGE("  point "  << pts[i]  << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " <<  coords[2]);
10856                 }
10857               if (distance2 < radius2)
10858                 {
10859                   volInside = true; // one or more nodes inside the domain
10860                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
10861                   break;
10862                 }
10863             }
10864           if (volInside)
10865             {
10866               setOfInsideVol.insert(vtkId);
10867               MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
10868               int neighborsVtkIds[NBMAXNEIGHBORS];
10869               int downIds[NBMAXNEIGHBORS];
10870               unsigned char downTypes[NBMAXNEIGHBORS];
10871               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10872               for (int n = 0; n < nbNeighbors; n++)
10873                 if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n]))
10874                   setOfVolToCheck.insert(neighborsVtkIds[n]);
10875             }
10876           else
10877             {
10878               setOfOutsideVol.insert(vtkId);
10879               MESSAGE("  volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
10880             }
10881           setOfVolToCheck.erase(vtkId);
10882         }
10883     }
10884
10885   // --- for outside hexahedrons, check if they have more than one neighbor volume inside
10886   //     If yes, add the volume to the inside set
10887
10888   bool addedInside = true;
10889   std::set<int> setOfVolToReCheck;
10890   while (addedInside)
10891     {
10892       MESSAGE(" --------------------------- re check");
10893       addedInside = false;
10894       std::set<int>::iterator itv = setOfInsideVol.begin();
10895       for (; itv != setOfInsideVol.end(); ++itv)
10896         {
10897           int vtkId = *itv;
10898           int neighborsVtkIds[NBMAXNEIGHBORS];
10899           int downIds[NBMAXNEIGHBORS];
10900           unsigned char downTypes[NBMAXNEIGHBORS];
10901           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10902           for (int n = 0; n < nbNeighbors; n++)
10903             if (!setOfInsideVol.count(neighborsVtkIds[n]))
10904               setOfVolToReCheck.insert(neighborsVtkIds[n]);
10905         }
10906       setOfVolToCheck = setOfVolToReCheck;
10907       setOfVolToReCheck.clear();
10908       while  (!setOfVolToCheck.empty())
10909         {
10910           std::set<int>::iterator it = setOfVolToCheck.begin();
10911           int vtkId = *it;
10912           if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON)
10913             {
10914               MESSAGE("volume to recheck,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
10915               int countInside = 0;
10916               int neighborsVtkIds[NBMAXNEIGHBORS];
10917               int downIds[NBMAXNEIGHBORS];
10918               unsigned char downTypes[NBMAXNEIGHBORS];
10919               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10920               for (int n = 0; n < nbNeighbors; n++)
10921                 if (setOfInsideVol.count(neighborsVtkIds[n]))
10922                   countInside++;
10923               MESSAGE("countInside " << countInside);
10924               if (countInside > 1)
10925                 {
10926                   MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
10927                   setOfInsideVol.insert(vtkId);
10928                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
10929                   addedInside = true;
10930                 }
10931               else
10932                 setOfVolToReCheck.insert(vtkId);
10933             }
10934           setOfVolToCheck.erase(vtkId);
10935         }
10936     }
10937
10938   // --- map of Downward faces at the boundary, inside the global volume
10939   //     map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin)
10940   //     fill group of SMDS faces inside the volume (when several volume shapes)
10941   //     fill group of SMDS faces on the skin of the global volume (if skin)
10942
10943   std::map<DownIdType, int, DownIdCompare> boundaryFaces; // boundary faces inside the volume --> corresponding cell
10944   std::map<DownIdType, int, DownIdCompare> skinFaces;     // faces on the skin of the global volume --> corresponding cell
10945   std::set<int>::iterator it = setOfInsideVol.begin();
10946   for (; it != setOfInsideVol.end(); ++it)
10947     {
10948       int vtkId = *it;
10949       //MESSAGE("  vtkId " << vtkId  << " smdsId " << meshDS->fromVtkToSmds(vtkId));
10950       int neighborsVtkIds[NBMAXNEIGHBORS];
10951       int downIds[NBMAXNEIGHBORS];
10952       unsigned char downTypes[NBMAXNEIGHBORS];
10953       int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true);
10954       for (int n = 0; n < nbNeighbors; n++)
10955         {
10956           int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n]));
10957           if (neighborDim == 3)
10958             {
10959               if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary
10960                 {
10961                   DownIdType face(downIds[n], downTypes[n]);
10962                   boundaryFaces[face] = vtkId;
10963                 }
10964               // if the face between to volumes is in the mesh, get it (internal face between shapes)
10965               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
10966               if (vtkFaceId >= 0)
10967                 {
10968                   sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId));
10969                   // find also the smds edges on this face
10970                   int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]);
10971                   const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]);
10972                   const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]);
10973                   for (int i = 0; i < nbEdges; i++)
10974                     {
10975                       int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]);
10976                       if (vtkEdgeId >= 0)
10977                         sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId));
10978                     }
10979                 }
10980             }
10981           else if (neighborDim == 2) // skin of the volume
10982             {
10983               DownIdType face(downIds[n], downTypes[n]);
10984               skinFaces[face] = vtkId;
10985               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
10986               if (vtkFaceId >= 0)
10987                 sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId));
10988             }
10989         }
10990     }
10991
10992   // --- identify the edges constituting the wire of each subshape on the skin
10993   //     define polylines with the nodes of edges, equivalent to wires
10994   //     project polylines on subshapes, and partition, to get geom faces
10995
10996   std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
10997   std::set<int> emptySet;
10998   emptySet.clear();
10999   std::set<int> shapeIds;
11000
11001   SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
11002   while (itelem->more())
11003     {
11004       const SMDS_MeshElement *elem = itelem->next();
11005       int shapeId = elem->getshapeId();
11006       int vtkId = elem->getVtkId();
11007       if (!shapeIdToVtkIdSet.count(shapeId))
11008         {
11009           shapeIdToVtkIdSet[shapeId] = emptySet;
11010           shapeIds.insert(shapeId);
11011         }
11012       shapeIdToVtkIdSet[shapeId].insert(vtkId);
11013     }
11014
11015   std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
11016   std::set<DownIdType, DownIdCompare> emptyEdges;
11017   emptyEdges.clear();
11018
11019   std::map<int, std::set<int> >::iterator itShape =  shapeIdToVtkIdSet.begin();
11020   for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
11021     {
11022       int shapeId = itShape->first;
11023       MESSAGE(" --- Shape ID --- "<< shapeId);
11024       shapeIdToEdges[shapeId] = emptyEdges;
11025
11026       std::vector<int> nodesEdges;
11027
11028       std::set<int>::iterator its = itShape->second.begin();
11029       for (; its != itShape->second.end(); ++its)
11030         {
11031           int vtkId = *its;
11032           MESSAGE("     " << vtkId);
11033           int neighborsVtkIds[NBMAXNEIGHBORS];
11034           int downIds[NBMAXNEIGHBORS];
11035           unsigned char downTypes[NBMAXNEIGHBORS];
11036           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11037           for (int n = 0; n < nbNeighbors; n++)
11038             {
11039               if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
11040                 continue;
11041               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
11042               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11043               if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
11044                 {
11045                   DownIdType edge(downIds[n], downTypes[n]);
11046                   if (!shapeIdToEdges[shapeId].count(edge))
11047                     {
11048                       shapeIdToEdges[shapeId].insert(edge);
11049                       int vtkNodeId[3];
11050                       int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId);
11051                       nodesEdges.push_back(vtkNodeId[0]);
11052                       nodesEdges.push_back(vtkNodeId[nbNodes-1]);
11053                       MESSAGE("       --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1);
11054                     }
11055                 }
11056             }
11057         }
11058
11059       std::list<int> order;
11060       order.clear();
11061       if (nodesEdges.size() > 0)
11062         {
11063           order.push_back(nodesEdges[0]); MESSAGE("       --- back " << order.back()+1); // SMDS id = VTK id + 1;
11064           nodesEdges[0] = -1;
11065           order.push_back(nodesEdges[1]); MESSAGE("       --- back " << order.back()+1);
11066           nodesEdges[1] = -1; // do not reuse this edge
11067           bool found = true;
11068           while (found)
11069             {
11070               int nodeTofind = order.back(); // try first to push back
11071               int i = 0;
11072               for (i = 0; i<nodesEdges.size(); i++)
11073                 if (nodesEdges[i] == nodeTofind)
11074                   break;
11075               if (i == nodesEdges.size())
11076                 found = false; // no follower found on back
11077               else
11078                 {
11079                   if (i%2) // odd ==> use the previous one
11080                     if (nodesEdges[i-1] < 0)
11081                       found = false;
11082                     else
11083                       {
11084                         order.push_back(nodesEdges[i-1]); MESSAGE("       --- back " << order.back()+1);
11085                         nodesEdges[i-1] = -1;
11086                       }
11087                   else // even ==> use the next one
11088                     if (nodesEdges[i+1] < 0)
11089                       found = false;
11090                     else
11091                       {
11092                         order.push_back(nodesEdges[i+1]); MESSAGE("       --- back " << order.back()+1);
11093                         nodesEdges[i+1] = -1;
11094                       }
11095                 }
11096               if (found)
11097                 continue;
11098               // try to push front
11099               found = true;
11100               nodeTofind = order.front(); // try to push front
11101               for (i = 0; i<nodesEdges.size(); i++)
11102                 if (nodesEdges[i] == nodeTofind)
11103                   break;
11104               if (i == nodesEdges.size())
11105                 {
11106                   found = false; // no predecessor found on front
11107                   continue;
11108                 }
11109               if (i%2) // odd ==> use the previous one
11110                 if (nodesEdges[i-1] < 0)
11111                   found = false;
11112                 else
11113                   {
11114                     order.push_front(nodesEdges[i-1]); MESSAGE("       --- front " << order.front()+1);
11115                     nodesEdges[i-1] = -1;
11116                   }
11117               else // even ==> use the next one
11118                 if (nodesEdges[i+1] < 0)
11119                   found = false;
11120                 else
11121                   {
11122                     order.push_front(nodesEdges[i+1]); MESSAGE("       --- front " << order.front()+1);
11123                     nodesEdges[i+1] = -1;
11124                   }
11125             }
11126         }
11127
11128
11129       std::vector<int> nodes;
11130       nodes.push_back(shapeId);
11131       std::list<int>::iterator itl = order.begin();
11132       for (; itl != order.end(); itl++)
11133         {
11134           nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
11135           MESSAGE("              ordered node " << nodes[nodes.size()-1]);
11136         }
11137       listOfListOfNodes.push_back(nodes);
11138     }
11139
11140   //     partition geom faces with blocFissure
11141   //     mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose)
11142   //     mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose)
11143
11144   return;
11145 }
11146
11147
11148 //================================================================================
11149 /*!
11150  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11151  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11152  * \return TRUE if operation has been completed successfully, FALSE otherwise
11153  */
11154 //================================================================================
11155
11156 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11157 {
11158   // iterates on volume elements and detect all free faces on them
11159   SMESHDS_Mesh* aMesh = GetMeshDS();
11160   if (!aMesh)
11161     return false;
11162   //bool res = false;
11163   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11164   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11165   while(vIt->more())
11166   {
11167     const SMDS_MeshVolume* volume = vIt->next();
11168     SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
11169     vTool.SetExternalNormal();
11170     //const bool isPoly = volume->IsPoly();
11171     const int iQuad = volume->IsQuadratic();
11172     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11173     {
11174       if (!vTool.IsFreeFace(iface))
11175         continue;
11176       nbFree++;
11177       vector<const SMDS_MeshNode *> nodes;
11178       int nbFaceNodes = vTool.NbFaceNodes(iface);
11179       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11180       int inode = 0;
11181       for ( ; inode < nbFaceNodes; inode += iQuad+1)
11182         nodes.push_back(faceNodes[inode]);
11183       if (iQuad) { // add medium nodes
11184         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11185           nodes.push_back(faceNodes[inode]);
11186         if ( nbFaceNodes == 9 ) // bi-quadratic quad
11187           nodes.push_back(faceNodes[8]);
11188       }
11189       // add new face based on volume nodes
11190       if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
11191         nbExisted++;
11192         continue; // face already exsist
11193       }
11194       AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
11195       nbCreated++;
11196     }
11197   }
11198   return ( nbFree==(nbExisted+nbCreated) );
11199 }
11200
11201 namespace
11202 {
11203   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11204   {
11205     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11206       return n;
11207     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11208   }
11209 }
11210 //================================================================================
11211 /*!
11212  * \brief Creates missing boundary elements
11213  *  \param elements - elements whose boundary is to be checked
11214  *  \param dimension - defines type of boundary elements to create
11215  *  \param group - a group to store created boundary elements in
11216  *  \param targetMesh - a mesh to store created boundary elements in
11217  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11218  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
11219  *                                boundary elements will be copied into the targetMesh
11220  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11221  *                                boundary elements will be added into the new group
11222  *  \param aroundElements - if true, elements will be created on boundary of given
11223  *                          elements else, on boundary of the whole mesh.
11224  * \return nb of added boundary elements
11225  */
11226 //================================================================================
11227
11228 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11229                                        Bnd_Dimension           dimension,
11230                                        SMESH_Group*            group/*=0*/,
11231                                        SMESH_Mesh*             targetMesh/*=0*/,
11232                                        bool                    toCopyElements/*=false*/,
11233                                        bool                    toCopyExistingBoundary/*=false*/,
11234                                        bool                    toAddExistingBondary/*= false*/,
11235                                        bool                    aroundElements/*= false*/)
11236 {
11237   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11238   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11239   // hope that all elements are of the same type, do not check them all
11240   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11241     throw SALOME_Exception(LOCALIZED("wrong element type"));
11242
11243   if ( !targetMesh )
11244     toCopyElements = toCopyExistingBoundary = false;
11245
11246   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11247   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11248   int nbAddedBnd = 0;
11249
11250   // editor adding present bnd elements and optionally holding elements to add to the group
11251   SMESH_MeshEditor* presentEditor;
11252   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11253   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11254
11255   SMESH_MesherHelper helper( *myMesh );
11256   const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
11257   SMDS_VolumeTool vTool;
11258   TIDSortedElemSet avoidSet;
11259   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11260   int inode;
11261
11262   typedef vector<const SMDS_MeshNode*> TConnectivity;
11263
11264   SMDS_ElemIteratorPtr eIt;
11265   if (elements.empty())
11266     eIt = aMesh->elementsIterator(elemType);
11267   else
11268     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11269
11270   while (eIt->more())
11271   {
11272     const SMDS_MeshElement* elem = eIt->next();
11273     const int              iQuad = elem->IsQuadratic();
11274
11275     // ------------------------------------------------------------------------------------
11276     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11277     // ------------------------------------------------------------------------------------
11278     vector<const SMDS_MeshElement*> presentBndElems;
11279     vector<TConnectivity>           missingBndElems;
11280     TConnectivity nodes, elemNodes;
11281     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
11282     {
11283       vTool.SetExternalNormal();
11284       const SMDS_MeshElement* otherVol = 0;
11285       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11286       {
11287         if ( !vTool.IsFreeFace(iface, &otherVol) &&
11288              ( !aroundElements || elements.count( otherVol )))
11289           continue;
11290         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11291         const int    nbFaceNodes = vTool.NbFaceNodes (iface);
11292         if ( missType == SMDSAbs_Edge ) // boundary edges
11293         {
11294           nodes.resize( 2+iQuad );
11295           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11296           {
11297             for ( int j = 0; j < nodes.size(); ++j )
11298               nodes[j] =nn[i+j];
11299             if ( const SMDS_MeshElement* edge =
11300                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11301               presentBndElems.push_back( edge );
11302             else
11303               missingBndElems.push_back( nodes );
11304           }
11305         }
11306         else // boundary face
11307         {
11308           nodes.clear();
11309           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11310             nodes.push_back( nn[inode] ); // add corner nodes
11311           if (iQuad)
11312             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11313               nodes.push_back( nn[inode] ); // add medium nodes
11314           int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
11315           if ( iCenter > 0 )
11316             nodes.push_back( vTool.GetNodes()[ iCenter ] );
11317
11318           if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
11319                                                                SMDSAbs_Face, /*noMedium=*/false ))
11320             presentBndElems.push_back( f );
11321           else
11322             missingBndElems.push_back( nodes );
11323
11324           if ( targetMesh != myMesh )
11325           {
11326             // add 1D elements on face boundary to be added to a new mesh
11327             const SMDS_MeshElement* edge;
11328             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11329             {
11330               if ( iQuad )
11331                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11332               else
11333                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11334               if ( edge && avoidSet.insert( edge ).second )
11335                 presentBndElems.push_back( edge );
11336             }
11337           }
11338         }
11339       }
11340     }
11341     else if ( elem->GetType() == SMDSAbs_Face ) // elem is a face ------------------------
11342     {
11343       avoidSet.clear(), avoidSet.insert( elem );
11344       elemNodes.assign( SMDS_MeshElement::iterator( elem->interlacedNodesElemIterator() ),
11345                         SMDS_MeshElement::iterator() );
11346       elemNodes.push_back( elemNodes[0] );
11347       nodes.resize( 2 + iQuad );
11348       const int nbLinks = elem->NbCornerNodes();
11349       for ( int i = 0, iN = 0; i < nbLinks; i++, iN += 1+iQuad )
11350       {
11351         nodes[0] = elemNodes[iN];
11352         nodes[1] = elemNodes[iN+1+iQuad];
11353         if ( SMESH_MeshAlgos::FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11354           continue; // not free link
11355
11356         if ( iQuad ) nodes[2] = elemNodes[iN+1];
11357         if ( const SMDS_MeshElement* edge =
11358              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11359           presentBndElems.push_back( edge );
11360         else
11361           missingBndElems.push_back( nodes );
11362       }
11363     }
11364
11365     // ---------------------------------
11366     // 2. Add missing boundary elements
11367     // ---------------------------------
11368     if ( targetMesh != myMesh )
11369       // instead of making a map of nodes in this mesh and targetMesh,
11370       // we create nodes with same IDs.
11371       for ( int i = 0; i < missingBndElems.size(); ++i )
11372       {
11373         TConnectivity& srcNodes = missingBndElems[i];
11374         TConnectivity  nodes( srcNodes.size() );
11375         for ( inode = 0; inode < nodes.size(); ++inode )
11376           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11377         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11378                                                                    missType,
11379                                                                    /*noMedium=*/false))
11380           continue;
11381         tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11382         ++nbAddedBnd;
11383       }
11384     else
11385       for ( int i = 0; i < missingBndElems.size(); ++i )
11386       {
11387         TConnectivity& nodes = missingBndElems[i];
11388         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11389                                                                    missType,
11390                                                                    /*noMedium=*/false))
11391           continue;
11392         SMDS_MeshElement* elem =
11393           tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11394         ++nbAddedBnd;
11395
11396         // try to set a new element to a shape
11397         if ( myMesh->HasShapeToMesh() )
11398         {
11399           bool ok = true;
11400           set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
11401           const int nbN = nodes.size() / (iQuad+1 );
11402           for ( inode = 0; inode < nbN && ok; ++inode )
11403           {
11404             pair<int, TopAbs_ShapeEnum> i_stype =
11405               helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
11406             if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
11407               mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
11408           }
11409           if ( ok && mediumShapes.size() > 1 )
11410           {
11411             set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
11412             pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
11413             for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
11414             {
11415               if (( ok = ( stype_i->first != stype_i_0.first )))
11416                 ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
11417                                         aMesh->IndexToShape( stype_i_0.second ));
11418             }
11419           }
11420           if ( ok && mediumShapes.begin()->first == missShapeType )
11421             aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
11422         }
11423       }
11424
11425     // ----------------------------------
11426     // 3. Copy present boundary elements
11427     // ----------------------------------
11428     if ( toCopyExistingBoundary )
11429       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11430       {
11431         const SMDS_MeshElement* e = presentBndElems[i];
11432         TConnectivity nodes( e->NbNodes() );
11433         for ( inode = 0; inode < nodes.size(); ++inode )
11434           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11435         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11436       }
11437     else // store present elements to add them to a group
11438       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11439       {
11440         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11441       }
11442
11443   } // loop on given elements
11444
11445   // ---------------------------------------------
11446   // 4. Fill group with boundary elements
11447   // ---------------------------------------------
11448   if ( group )
11449   {
11450     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11451       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11452         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11453   }
11454   tgtEditor.myLastCreatedElems.Clear();
11455   tgtEditor2.myLastCreatedElems.Clear();
11456
11457   // -----------------------
11458   // 5. Copy given elements
11459   // -----------------------
11460   if ( toCopyElements && targetMesh != myMesh )
11461   {
11462     if (elements.empty())
11463       eIt = aMesh->elementsIterator(elemType);
11464     else
11465       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11466     while (eIt->more())
11467     {
11468       const SMDS_MeshElement* elem = eIt->next();
11469       TConnectivity nodes( elem->NbNodes() );
11470       for ( inode = 0; inode < nodes.size(); ++inode )
11471         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11472       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11473
11474       tgtEditor.myLastCreatedElems.Clear();
11475     }
11476   }
11477   return nbAddedBnd;
11478 }