Salome HOME
1d5698d249bc67e59ed207f38ab86ebc735811ca
[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 namespace
107 {
108   template < class ELEM_SET >
109   SMDS_ElemIteratorPtr elemSetIterator( const ELEM_SET& elements )
110   {
111     typedef SMDS_SetIterator
112       < SMDS_pElement, typename ELEM_SET::const_iterator> TSetIterator;
113     return SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
114   }
115 }
116
117 //=======================================================================
118 //function : SMESH_MeshEditor
119 //purpose  :
120 //=======================================================================
121
122 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
123   :myMesh( theMesh ) // theMesh may be NULL
124 {
125 }
126
127 //================================================================================
128 /*!
129  * \brief Clears myLastCreatedNodes and myLastCreatedElems
130  */
131 //================================================================================
132
133 void SMESH_MeshEditor::CrearLastCreated()
134 {
135   myLastCreatedNodes.Clear();
136   myLastCreatedElems.Clear();
137 }
138
139
140 //=======================================================================
141 /*!
142  * \brief Add element
143  */
144 //=======================================================================
145
146 SMDS_MeshElement*
147 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
148                              const SMDSAbs_ElementType            type,
149                              const bool                           isPoly,
150                              const int                            ID,
151                              const double                         ballDiameter)
152 {
153   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
154   SMDS_MeshElement* e = 0;
155   int nbnode = node.size();
156   SMESHDS_Mesh* mesh = GetMeshDS();
157   switch ( type ) {
158   case SMDSAbs_Face:
159     if ( !isPoly ) {
160       if      (nbnode == 3) {
161         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
162         else           e = mesh->AddFace      (node[0], node[1], node[2] );
163       }
164       else if (nbnode == 4) {
165         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
166         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
167       }
168       else if (nbnode == 6) {
169         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
170                                                node[4], node[5], ID);
171         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
172                                                node[4], node[5] );
173       }
174       else if (nbnode == 7) {
175         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
176                                                node[4], node[5], node[6], ID);
177         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
178                                                node[4], node[5], node[6] );
179       }
180       else if (nbnode == 8) {
181         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
182                                                node[4], node[5], node[6], node[7], ID);
183         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
184                                                node[4], node[5], node[6], node[7] );
185       }
186       else if (nbnode == 9) {
187         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
188                                                node[4], node[5], node[6], node[7], node[8], ID);
189         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
190                                                node[4], node[5], node[6], node[7], node[8] );
191       }
192     } else {
193       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
194       else           e = mesh->AddPolygonalFace      (node    );
195     }
196     break;
197
198   case SMDSAbs_Volume:
199     if ( !isPoly ) {
200       if      (nbnode == 4) {
201         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
202         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
203       }
204       else if (nbnode == 5) {
205         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
206                                                  node[4], ID);
207         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
208                                                  node[4] );
209       }
210       else if (nbnode == 6) {
211         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
212                                                  node[4], node[5], ID);
213         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
214                                                  node[4], node[5] );
215       }
216       else if (nbnode == 8) {
217         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
218                                                  node[4], node[5], node[6], node[7], ID);
219         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
220                                                  node[4], node[5], node[6], node[7] );
221       }
222       else if (nbnode == 10) {
223         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
224                                                  node[4], node[5], node[6], node[7],
225                                                  node[8], node[9], ID);
226         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
227                                                  node[4], node[5], node[6], node[7],
228                                                  node[8], node[9] );
229       }
230       else if (nbnode == 12) {
231         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
232                                                  node[4], node[5], node[6], node[7],
233                                                  node[8], node[9], node[10], node[11], 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       }
238       else if (nbnode == 13) {
239         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
240                                                  node[4], node[5], node[6], node[7],
241                                                  node[8], node[9], node[10],node[11],
242                                                  node[12],ID);
243         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
244                                                  node[4], node[5], node[6], node[7],
245                                                  node[8], node[9], node[10],node[11],
246                                                  node[12] );
247       }
248       else if (nbnode == 15) {
249         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
250                                                  node[4], node[5], node[6], node[7],
251                                                  node[8], node[9], node[10],node[11],
252                                                  node[12],node[13],node[14],ID);
253         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
254                                                  node[4], node[5], node[6], node[7],
255                                                  node[8], node[9], node[10],node[11],
256                                                  node[12],node[13],node[14] );
257       }
258       else if (nbnode == 20) {
259         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
260                                                  node[4], node[5], node[6], node[7],
261                                                  node[8], node[9], node[10],node[11],
262                                                  node[12],node[13],node[14],node[15],
263                                                  node[16],node[17],node[18],node[19],ID);
264         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
265                                                  node[4], node[5], node[6], node[7],
266                                                  node[8], node[9], node[10],node[11],
267                                                  node[12],node[13],node[14],node[15],
268                                                  node[16],node[17],node[18],node[19] );
269       }
270       else if (nbnode == 27) {
271         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
272                                                  node[4], node[5], node[6], node[7],
273                                                  node[8], node[9], node[10],node[11],
274                                                  node[12],node[13],node[14],node[15],
275                                                  node[16],node[17],node[18],node[19],
276                                                  node[20],node[21],node[22],node[23],
277                                                  node[24],node[25],node[26], ID);
278         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
279                                                  node[4], node[5], node[6], node[7],
280                                                  node[8], node[9], node[10],node[11],
281                                                  node[12],node[13],node[14],node[15],
282                                                  node[16],node[17],node[18],node[19],
283                                                  node[20],node[21],node[22],node[23],
284                                                  node[24],node[25],node[26] );
285       }
286     }
287     break;
288
289   case SMDSAbs_Edge:
290     if ( nbnode == 2 ) {
291       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
292       else           e = mesh->AddEdge      (node[0], node[1] );
293     }
294     else if ( nbnode == 3 ) {
295       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
296       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
297     }
298     break;
299
300   case SMDSAbs_0DElement:
301     if ( nbnode == 1 ) {
302       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
303       else           e = mesh->Add0DElement      (node[0] );
304     }
305     break;
306
307   case SMDSAbs_Node:
308     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
309     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
310     break;
311
312   case SMDSAbs_Ball:
313     if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], ballDiameter, ID);
314     else           e = mesh->AddBall      (node[0], ballDiameter);
315     break;
316
317   default:;
318   }
319   if ( e ) myLastCreatedElems.Append( e );
320   return e;
321 }
322
323 //=======================================================================
324 /*!
325  * \brief Add element
326  */
327 //=======================================================================
328
329 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
330                                                const SMDSAbs_ElementType type,
331                                                const bool                isPoly,
332                                                const int                 ID)
333 {
334   vector<const SMDS_MeshNode*> nodes;
335   nodes.reserve( nodeIDs.size() );
336   vector<int>::const_iterator id = nodeIDs.begin();
337   while ( id != nodeIDs.end() ) {
338     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
339       nodes.push_back( node );
340     else
341       return 0;
342   }
343   return AddElement( nodes, type, isPoly, ID );
344 }
345
346 //=======================================================================
347 //function : Remove
348 //purpose  : Remove a node or an element.
349 //           Modify a compute state of sub-meshes which become empty
350 //=======================================================================
351
352 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
353                               const bool         isNodes )
354 {
355   myLastCreatedElems.Clear();
356   myLastCreatedNodes.Clear();
357
358   SMESHDS_Mesh* aMesh = GetMeshDS();
359   set< SMESH_subMesh *> smmap;
360
361   int removed = 0;
362   list<int>::const_iterator it = theIDs.begin();
363   for ( ; it != theIDs.end(); it++ ) {
364     const SMDS_MeshElement * elem;
365     if ( isNodes )
366       elem = aMesh->FindNode( *it );
367     else
368       elem = aMesh->FindElement( *it );
369     if ( !elem )
370       continue;
371
372     // Notify VERTEX sub-meshes about modification
373     if ( isNodes ) {
374       const SMDS_MeshNode* node = cast2Node( elem );
375       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
376         if ( int aShapeID = node->getshapeId() )
377           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
378             smmap.insert( sm );
379     }
380     // Find sub-meshes to notify about modification
381     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
382     //     while ( nodeIt->more() ) {
383     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
384     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
385     //       if ( aPosition.get() ) {
386     //         if ( int aShapeID = aPosition->GetShapeId() ) {
387     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
388     //             smmap.insert( sm );
389     //         }
390     //       }
391     //     }
392
393     // Do remove
394     if ( isNodes )
395       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
396     else
397       aMesh->RemoveElement( elem );
398     removed++;
399   }
400
401   // Notify sub-meshes about modification
402   if ( !smmap.empty() ) {
403     set< SMESH_subMesh *>::iterator smIt;
404     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
405       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
406   }
407
408   //   // Check if the whole mesh becomes empty
409   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
410   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
411
412   return removed;
413 }
414
415 //================================================================================
416 /*!
417  * \brief Create 0D elements on all nodes of the given object except those
418  *        nodes on which a 0D element already exists.
419  *  \param elements - Elements on whose nodes to create 0D elements; if empty, 
420  *                    the all mesh is treated
421  *  \param all0DElems - returns all 0D elements found or created on nodes of \a elements
422  */
423 //================================================================================
424
425 void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements,
426                                                    TIDSortedElemSet&       all0DElems )
427 {
428   SMDS_ElemIteratorPtr elemIt;
429   vector< const SMDS_MeshElement* > allNodes;
430   if ( elements.empty() )
431   {
432     allNodes.reserve( GetMeshDS()->NbNodes() );
433     elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node );
434     while ( elemIt->more() )
435       allNodes.push_back( elemIt->next() );
436
437     elemIt = elemSetIterator( allNodes );
438   }
439   else
440   {
441     elemIt = elemSetIterator( elements );
442   }
443
444   while ( elemIt->more() )
445   {
446     const SMDS_MeshElement* e = elemIt->next();
447     SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
448     while ( nodeIt->more() )
449     {
450       const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
451       SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement );
452       if ( it0D->more() )
453         all0DElems.insert( it0D->next() );
454       else {
455         myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n ));
456         all0DElems.insert( myLastCreatedElems.Last() );
457       }
458     }
459   }
460 }
461
462 //=======================================================================
463 //function : FindShape
464 //purpose  : Return an index of the shape theElem is on
465 //           or zero if a shape not found
466 //=======================================================================
467
468 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
469 {
470   myLastCreatedElems.Clear();
471   myLastCreatedNodes.Clear();
472
473   SMESHDS_Mesh * aMesh = GetMeshDS();
474   if ( aMesh->ShapeToMesh().IsNull() )
475     return 0;
476
477   int aShapeID = theElem->getshapeId();
478   if ( aShapeID < 1 )
479     return 0;
480
481   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
482     if ( sm->Contains( theElem ))
483       return aShapeID;
484
485   if ( theElem->GetType() == SMDSAbs_Node ) {
486     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
487   }
488   else {
489     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
490   }
491
492   TopoDS_Shape aShape; // the shape a node of theElem is on
493   if ( theElem->GetType() != SMDSAbs_Node )
494   {
495     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
496     while ( nodeIt->more() ) {
497       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
498       if ((aShapeID = node->getshapeId()) > 0) {
499         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
500           if ( sm->Contains( theElem ))
501             return aShapeID;
502           if ( aShape.IsNull() )
503             aShape = aMesh->IndexToShape( aShapeID );
504         }
505       }
506     }
507   }
508
509   // None of nodes is on a proper shape,
510   // find the shape among ancestors of aShape on which a node is
511   if ( !aShape.IsNull() ) {
512     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
513     for ( ; ancIt.More(); ancIt.Next() ) {
514       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
515       if ( sm && sm->Contains( theElem ))
516         return aMesh->ShapeToIndex( ancIt.Value() );
517     }
518   }
519   else
520   {
521     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
522     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
523     for ( ; id_sm != id2sm.end(); ++id_sm )
524       if ( id_sm->second->Contains( theElem ))
525         return id_sm->first;
526   }
527
528   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
529   return 0;
530 }
531
532 //=======================================================================
533 //function : IsMedium
534 //purpose  :
535 //=======================================================================
536
537 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
538                                 const SMDSAbs_ElementType typeToCheck)
539 {
540   bool isMedium = false;
541   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
542   while (it->more() && !isMedium ) {
543     const SMDS_MeshElement* elem = it->next();
544     isMedium = elem->IsMediumNode(node);
545   }
546   return isMedium;
547 }
548
549 //=======================================================================
550 //function : shiftNodesQuadTria
551 //purpose  : Shift nodes in the array corresponded to quadratic triangle
552 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
553 //=======================================================================
554
555 static void shiftNodesQuadTria(vector< const SMDS_MeshNode* >& aNodes)
556 {
557   const SMDS_MeshNode* nd1 = aNodes[0];
558   aNodes[0] = aNodes[1];
559   aNodes[1] = aNodes[2];
560   aNodes[2] = nd1;
561   const SMDS_MeshNode* nd2 = aNodes[3];
562   aNodes[3] = aNodes[4];
563   aNodes[4] = aNodes[5];
564   aNodes[5] = nd2;
565 }
566
567 //=======================================================================
568 //function : nbEdgeConnectivity
569 //purpose  : return number of the edges connected with the theNode.
570 //           if theEdges has connections with the other type of the
571 //           elements, return -1
572 //=======================================================================
573
574 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
575 {
576   // SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
577   // int nb=0;
578   // while(elemIt->more()) {
579   //   elemIt->next();
580   //   nb++;
581   // }
582   // return nb;
583   return theNode->NbInverseElements();
584 }
585
586 //=======================================================================
587 //function : getNodesFromTwoTria
588 //purpose  : 
589 //=======================================================================
590
591 static bool getNodesFromTwoTria(const SMDS_MeshElement * theTria1,
592                                 const SMDS_MeshElement * theTria2,
593                                 vector< const SMDS_MeshNode*>& N1,
594                                 vector< const SMDS_MeshNode*>& N2)
595 {
596   N1.assign( theTria1->begin_nodes(), theTria1->end_nodes() );
597   if ( N1.size() < 6 ) return false;
598   N2.assign( theTria2->begin_nodes(), theTria2->end_nodes() );
599   if ( N2.size() < 6 ) return false;
600
601   int sames[3] = {-1,-1,-1};
602   int nbsames = 0;
603   int i, j;
604   for(i=0; i<3; i++) {
605     for(j=0; j<3; j++) {
606       if(N1[i]==N2[j]) {
607         sames[i] = j;
608         nbsames++;
609         break;
610       }
611     }
612   }
613   if(nbsames!=2) return false;
614   if(sames[0]>-1) {
615     shiftNodesQuadTria(N1);
616     if(sames[1]>-1) {
617       shiftNodesQuadTria(N1);
618     }
619   }
620   i = sames[0] + sames[1] + sames[2];
621   for(; i<2; i++) {
622     shiftNodesQuadTria(N2);
623   }
624   // now we receive following N1 and N2 (using numeration as in the image below)
625   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
626   // i.e. first nodes from both arrays form a new diagonal
627   return true;
628 }
629
630 //=======================================================================
631 //function : InverseDiag
632 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
633 //           but having other common link.
634 //           Return False if args are improper
635 //=======================================================================
636
637 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
638                                     const SMDS_MeshElement * theTria2 )
639 {
640   MESSAGE("InverseDiag");
641   myLastCreatedElems.Clear();
642   myLastCreatedNodes.Clear();
643
644   if (!theTria1 || !theTria2)
645     return false;
646
647   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
648   if (!F1) return false;
649   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
650   if (!F2) return false;
651   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
652       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
653
654     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
655     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
656     //    |/ |                                         | \|
657     //  B +--+ 2                                     B +--+ 2
658
659     // put nodes in array and find out indices of the same ones
660     const SMDS_MeshNode* aNodes [6];
661     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
662     int i = 0;
663     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
664     while ( it->more() ) {
665       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
666
667       if ( i > 2 ) // theTria2
668         // find same node of theTria1
669         for ( int j = 0; j < 3; j++ )
670           if ( aNodes[ i ] == aNodes[ j ]) {
671             sameInd[ j ] = i;
672             sameInd[ i ] = j;
673             break;
674           }
675       // next
676       i++;
677       if ( i == 3 ) {
678         if ( it->more() )
679           return false; // theTria1 is not a triangle
680         it = theTria2->nodesIterator();
681       }
682       if ( i == 6 && it->more() )
683         return false; // theTria2 is not a triangle
684     }
685
686     // find indices of 1,2 and of A,B in theTria1
687     int iA = 0, iB = 0, i1 = 0, i2 = 0;
688     for ( i = 0; i < 6; i++ ) {
689       if ( sameInd [ i ] == 0 ) {
690         if ( i < 3 ) i1 = i;
691         else         i2 = i;
692       }
693       else if (i < 3) {
694         if ( iA ) iB = i;
695         else      iA = i;
696       }
697     }
698     // nodes 1 and 2 should not be the same
699     if ( aNodes[ i1 ] == aNodes[ i2 ] )
700       return false;
701
702     // theTria1: A->2
703     aNodes[ iA ] = aNodes[ i2 ];
704     // theTria2: B->1
705     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
706
707     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
708     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
709
710     return true;
711
712   } // end if(F1 && F2)
713
714   // check case of quadratic faces
715   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle &&
716       theTria1->GetEntityType() != SMDSEntity_BiQuad_Triangle)
717     return false;
718   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle&&
719       theTria2->GetEntityType() != SMDSEntity_BiQuad_Triangle)
720     return false;
721
722   //       5
723   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
724   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
725   //    |   / |
726   //  7 +  +  + 6
727   //    | /9  |
728   //    |/    |
729   //  4 +--+--+ 3
730   //       8
731
732   vector< const SMDS_MeshNode* > N1;
733   vector< const SMDS_MeshNode* > N2;
734   if(!getNodesFromTwoTria(theTria1,theTria2,N1,N2))
735     return false;
736   // now we receive following N1 and N2 (using numeration as above image)
737   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
738   // i.e. first nodes from both arrays determ new diagonal
739
740   vector< const SMDS_MeshNode*> N1new( N1.size() );
741   vector< const SMDS_MeshNode*> N2new( N2.size() );
742   N1new.back() = N1.back(); // central node of biquadratic
743   N2new.back() = N2.back();
744   N1new[0] = N1[0];  N2new[0] = N1[0];
745   N1new[1] = N2[0];  N2new[1] = N1[1];
746   N1new[2] = N2[1];  N2new[2] = N2[0];
747   N1new[3] = N1[4];  N2new[3] = N1[3];
748   N1new[4] = N2[3];  N2new[4] = N2[5];
749   N1new[5] = N1[5];  N2new[5] = N1[4];
750   // change nodes in faces
751   GetMeshDS()->ChangeElementNodes( theTria1, &N1new[0], N1new.size() );
752   GetMeshDS()->ChangeElementNodes( theTria2, &N2new[0], N2new.size() );
753
754   // move the central node of biquadratic triangle
755   SMESH_MesherHelper helper( *GetMesh() );
756   for ( int is2nd = 0; is2nd < 2; ++is2nd )
757   {
758     const SMDS_MeshElement*         tria = is2nd ? theTria2 : theTria1;
759     vector< const SMDS_MeshNode*>& nodes = is2nd ? N2new : N1new;
760     if ( nodes.size() < 7 )
761       continue;
762     helper.SetSubShape( tria->getshapeId() );
763     const TopoDS_Face& F = TopoDS::Face( helper.GetSubShape() );
764     gp_Pnt xyz;
765     if ( F.IsNull() )
766     {
767       xyz = ( SMESH_TNodeXYZ( nodes[3] ) +
768               SMESH_TNodeXYZ( nodes[4] ) +
769               SMESH_TNodeXYZ( nodes[5] )) / 3.;
770     }
771     else
772     {
773       bool checkUV;
774       gp_XY uv = ( helper.GetNodeUV( F, nodes[3], nodes[2], &checkUV ) +
775                    helper.GetNodeUV( F, nodes[4], nodes[0], &checkUV ) +
776                    helper.GetNodeUV( F, nodes[5], nodes[1], &checkUV )) / 3.;
777       TopLoc_Location loc;
778       Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc);
779       xyz = S->Value( uv.X(), uv.Y() );
780       xyz.Transform( loc );
781       if ( nodes[6]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE &&  // set UV
782            nodes[6]->getshapeId() > 0 )
783         GetMeshDS()->SetNodeOnFace( nodes[6], nodes[6]->getshapeId(), uv.X(), uv.Y() );
784     }
785     GetMeshDS()->MoveNode( nodes[6], xyz.X(), xyz.Y(), xyz.Z() );
786   }
787   return true;
788 }
789
790 //=======================================================================
791 //function : findTriangles
792 //purpose  : find triangles sharing theNode1-theNode2 link
793 //=======================================================================
794
795 static bool findTriangles(const SMDS_MeshNode *    theNode1,
796                           const SMDS_MeshNode *    theNode2,
797                           const SMDS_MeshElement*& theTria1,
798                           const SMDS_MeshElement*& theTria2)
799 {
800   if ( !theNode1 || !theNode2 ) return false;
801
802   theTria1 = theTria2 = 0;
803
804   set< const SMDS_MeshElement* > emap;
805   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
806   while (it->more()) {
807     const SMDS_MeshElement* elem = it->next();
808     if ( elem->NbCornerNodes() == 3 )
809       emap.insert( elem );
810   }
811   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
812   while (it->more()) {
813     const SMDS_MeshElement* elem = it->next();
814     if ( emap.count( elem )) {
815       if ( !theTria1 )
816       {
817         theTria1 = elem;
818       }
819       else  
820       {
821         theTria2 = elem;
822         // theTria1 must be element with minimum ID
823         if ( theTria2->GetID() < theTria1->GetID() )
824           std::swap( theTria2, theTria1 );
825         return true;
826       }
827     }
828   }
829   return false;
830 }
831
832 //=======================================================================
833 //function : InverseDiag
834 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
835 //           with ones built on the same 4 nodes but having other common link.
836 //           Return false if proper faces not found
837 //=======================================================================
838
839 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
840                                     const SMDS_MeshNode * theNode2)
841 {
842   myLastCreatedElems.Clear();
843   myLastCreatedNodes.Clear();
844
845   MESSAGE( "::InverseDiag()" );
846
847   const SMDS_MeshElement *tr1, *tr2;
848   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
849     return false;
850
851   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
852   if (!F1) return false;
853   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
854   if (!F2) return false;
855   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
856       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
857
858     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
859     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
860     //    |/ |                                    | \|
861     //  B +--+ 2                                B +--+ 2
862
863     // put nodes in array
864     // and find indices of 1,2 and of A in tr1 and of B in tr2
865     int i, iA1 = 0, i1 = 0;
866     const SMDS_MeshNode* aNodes1 [3];
867     SMDS_ElemIteratorPtr it;
868     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
869       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
870       if ( aNodes1[ i ] == theNode1 )
871         iA1 = i; // node A in tr1
872       else if ( aNodes1[ i ] != theNode2 )
873         i1 = i;  // node 1
874     }
875     int iB2 = 0, i2 = 0;
876     const SMDS_MeshNode* aNodes2 [3];
877     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
878       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
879       if ( aNodes2[ i ] == theNode2 )
880         iB2 = i; // node B in tr2
881       else if ( aNodes2[ i ] != theNode1 )
882         i2 = i;  // node 2
883     }
884
885     // nodes 1 and 2 should not be the same
886     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
887       return false;
888
889     // tr1: A->2
890     aNodes1[ iA1 ] = aNodes2[ i2 ];
891     // tr2: B->1
892     aNodes2[ iB2 ] = aNodes1[ i1 ];
893
894     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
895     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
896
897     return true;
898   }
899
900   // check case of quadratic faces
901   return InverseDiag(tr1,tr2);
902 }
903
904 //=======================================================================
905 //function : getQuadrangleNodes
906 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
907 //           fusion of triangles tr1 and tr2 having shared link on
908 //           theNode1 and theNode2
909 //=======================================================================
910
911 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
912                         const SMDS_MeshNode *    theNode1,
913                         const SMDS_MeshNode *    theNode2,
914                         const SMDS_MeshElement * tr1,
915                         const SMDS_MeshElement * tr2 )
916 {
917   if( tr1->NbNodes() != tr2->NbNodes() )
918     return false;
919   // find the 4-th node to insert into tr1
920   const SMDS_MeshNode* n4 = 0;
921   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
922   int i=0;
923   while ( !n4 && i<3 ) {
924     const SMDS_MeshNode * n = cast2Node( it->next() );
925     i++;
926     bool isDiag = ( n == theNode1 || n == theNode2 );
927     if ( !isDiag )
928       n4 = n;
929   }
930   // Make an array of nodes to be in a quadrangle
931   int iNode = 0, iFirstDiag = -1;
932   it = tr1->nodesIterator();
933   i=0;
934   while ( i<3 ) {
935     const SMDS_MeshNode * n = cast2Node( it->next() );
936     i++;
937     bool isDiag = ( n == theNode1 || n == theNode2 );
938     if ( isDiag ) {
939       if ( iFirstDiag < 0 )
940         iFirstDiag = iNode;
941       else if ( iNode - iFirstDiag == 1 )
942         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
943     }
944     else if ( n == n4 ) {
945       return false; // tr1 and tr2 should not have all the same nodes
946     }
947     theQuadNodes[ iNode++ ] = n;
948   }
949   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
950     theQuadNodes[ iNode ] = n4;
951
952   return true;
953 }
954
955 //=======================================================================
956 //function : DeleteDiag
957 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
958 //           with a quadrangle built on the same 4 nodes.
959 //           Return false if proper faces not found
960 //=======================================================================
961
962 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
963                                    const SMDS_MeshNode * theNode2)
964 {
965   myLastCreatedElems.Clear();
966   myLastCreatedNodes.Clear();
967
968   MESSAGE( "::DeleteDiag()" );
969
970   const SMDS_MeshElement *tr1, *tr2;
971   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
972     return false;
973
974   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
975   if (!F1) return false;
976   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
977   if (!F2) return false;
978   SMESHDS_Mesh * aMesh = GetMeshDS();
979
980   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
981       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
982
983     const SMDS_MeshNode* aNodes [ 4 ];
984     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
985       return false;
986
987     const SMDS_MeshElement* newElem = 0;
988     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
989     myLastCreatedElems.Append(newElem);
990     AddToSameGroups( newElem, tr1, aMesh );
991     int aShapeId = tr1->getshapeId();
992     if ( aShapeId )
993       {
994         aMesh->SetMeshElementOnShape( newElem, aShapeId );
995       }
996     aMesh->RemoveElement( tr1 );
997     aMesh->RemoveElement( tr2 );
998
999     return true;
1000   }
1001
1002   // check case of quadratic faces
1003   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
1004     return false;
1005   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
1006     return false;
1007
1008   //       5
1009   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
1010   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
1011   //    |   / |
1012   //  7 +  +  + 6
1013   //    | /9  |
1014   //    |/    |
1015   //  4 +--+--+ 3
1016   //       8
1017
1018   vector< const SMDS_MeshNode* > N1;
1019   vector< const SMDS_MeshNode* > N2;
1020   if(!getNodesFromTwoTria(tr1,tr2,N1,N2))
1021     return false;
1022   // now we receive following N1 and N2 (using numeration as above image)
1023   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
1024   // i.e. first nodes from both arrays determ new diagonal
1025
1026   const SMDS_MeshNode* aNodes[8];
1027   aNodes[0] = N1[0];
1028   aNodes[1] = N1[1];
1029   aNodes[2] = N2[0];
1030   aNodes[3] = N2[1];
1031   aNodes[4] = N1[3];
1032   aNodes[5] = N2[5];
1033   aNodes[6] = N2[3];
1034   aNodes[7] = N1[5];
1035
1036   const SMDS_MeshElement* newElem = 0;
1037   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
1038                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
1039   myLastCreatedElems.Append(newElem);
1040   AddToSameGroups( newElem, tr1, aMesh );
1041   int aShapeId = tr1->getshapeId();
1042   if ( aShapeId )
1043     {
1044       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1045     }
1046   aMesh->RemoveElement( tr1 );
1047   aMesh->RemoveElement( tr2 );
1048
1049   // remove middle node (9)
1050   GetMeshDS()->RemoveNode( N1[4] );
1051
1052   return true;
1053 }
1054
1055 //=======================================================================
1056 //function : Reorient
1057 //purpose  : Reverse theElement orientation
1058 //=======================================================================
1059
1060 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
1061 {
1062   MESSAGE("Reorient");
1063   myLastCreatedElems.Clear();
1064   myLastCreatedNodes.Clear();
1065
1066   if (!theElem)
1067     return false;
1068   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
1069   if ( !it || !it->more() )
1070     return false;
1071
1072   const SMDSAbs_ElementType type = theElem->GetType();
1073   if ( type < SMDSAbs_Edge || type > SMDSAbs_Volume )
1074     return false;
1075
1076   const SMDSAbs_EntityType geomType = theElem->GetEntityType();
1077   if ( geomType == SMDSEntity_Polyhedra ) // polyhedron
1078   {
1079     const SMDS_VtkVolume* aPolyedre =
1080       dynamic_cast<const SMDS_VtkVolume*>( theElem );
1081     if (!aPolyedre) {
1082       MESSAGE("Warning: bad volumic element");
1083       return false;
1084     }
1085     const int nbFaces = aPolyedre->NbFaces();
1086     vector<const SMDS_MeshNode *> poly_nodes;
1087     vector<int> quantities (nbFaces);
1088
1089     // reverse each face of the polyedre
1090     for (int iface = 1; iface <= nbFaces; iface++) {
1091       int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1092       quantities[iface - 1] = nbFaceNodes;
1093
1094       for (inode = nbFaceNodes; inode >= 1; inode--) {
1095         const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1096         poly_nodes.push_back(curNode);
1097       }
1098     }
1099     return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1100   }
1101   else // other elements
1102   {
1103     vector<const SMDS_MeshNode*> nodes( theElem->begin_nodes(), theElem->end_nodes() );
1104     const std::vector<int>& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType );
1105     if ( interlace.empty() )
1106     {
1107       std::reverse( nodes.begin(), nodes.end() ); // polygon
1108     }
1109     else if ( interlace.size() > 1 )
1110     {
1111       SMDS_MeshCell::applyInterlace( interlace, nodes );
1112     }
1113     return GetMeshDS()->ChangeElementNodes( theElem, &nodes[0], nodes.size() );
1114   }
1115   return false;
1116 }
1117
1118 //================================================================================
1119 /*!
1120  * \brief Reorient faces.
1121  * \param theFaces - the faces to reorient. If empty the whole mesh is meant
1122  * \param theDirection - desired direction of normal of \a theFace
1123  * \param theFace - one of \a theFaces that sould be oriented according to
1124  *        \a theDirection and whose orientation defines orientation of other faces
1125  * \return number of reoriented faces.
1126  */
1127 //================================================================================
1128
1129 int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
1130                                   const gp_Dir&            theDirection,
1131                                   const SMDS_MeshElement * theFace)
1132 {
1133   int nbReori = 0;
1134   if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori;
1135
1136   if ( theFaces.empty() )
1137   {
1138     SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true);
1139     while ( fIt->more() )
1140       theFaces.insert( theFaces.end(), fIt->next() );
1141   }
1142
1143   // orient theFace according to theDirection
1144   gp_XYZ normal;
1145   SMESH_MeshAlgos::FaceNormal( theFace, normal, /*normalized=*/false );
1146   if ( normal * theDirection.XYZ() < 0 )
1147     nbReori += Reorient( theFace );
1148
1149   // Orient other faces
1150
1151   set< const SMDS_MeshElement* > startFaces, visitedFaces;
1152   TIDSortedElemSet avoidSet;
1153   set< SMESH_TLink > checkedLinks;
1154   pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
1155
1156   if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
1157     theFaces.erase( theFace );
1158   startFaces.insert( theFace );
1159
1160   int nodeInd1, nodeInd2;
1161   const SMDS_MeshElement*           otherFace;
1162   vector< const SMDS_MeshElement* > facesNearLink;
1163   vector< std::pair< int, int > >   nodeIndsOfFace;
1164
1165   set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
1166   while ( !startFaces.empty() )
1167   {
1168     startFace = startFaces.begin();
1169     theFace = *startFace;
1170     startFaces.erase( startFace );
1171     if ( !visitedFaces.insert( theFace ).second )
1172       continue;
1173
1174     avoidSet.clear();
1175     avoidSet.insert(theFace);
1176
1177     NLink link( theFace->GetNode( 0 ), 0 );
1178
1179     const int nbNodes = theFace->NbCornerNodes();
1180     for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
1181     {
1182       link.second = theFace->GetNode(( i+1 ) % nbNodes );
1183       linkIt_isNew = checkedLinks.insert( link );
1184       if ( !linkIt_isNew.second )
1185       {
1186         // link has already been checked and won't be encountered more
1187         // if the group (theFaces) is manifold
1188         //checkedLinks.erase( linkIt_isNew.first );
1189       }
1190       else
1191       {
1192         facesNearLink.clear();
1193         nodeIndsOfFace.clear();
1194         while (( otherFace = SMESH_MeshAlgos::FindFaceInSet( link.first, link.second,
1195                                                              theFaces, avoidSet,
1196                                                              &nodeInd1, &nodeInd2 )))
1197           if ( otherFace != theFace)
1198           {
1199             facesNearLink.push_back( otherFace );
1200             nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 ));
1201             avoidSet.insert( otherFace );
1202           }
1203         if ( facesNearLink.size() > 1 )
1204         {
1205           // NON-MANIFOLD mesh shell !
1206           // select a face most co-directed with theFace,
1207           // other faces won't be visited this time
1208           gp_XYZ NF, NOF;
1209           SMESH_MeshAlgos::FaceNormal( theFace, NF, /*normalized=*/false );
1210           double proj, maxProj = -1;
1211           for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
1212             SMESH_MeshAlgos::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
1213             if (( proj = Abs( NF * NOF )) > maxProj ) {
1214               maxProj = proj;
1215               otherFace = facesNearLink[i];
1216               nodeInd1  = nodeIndsOfFace[i].first;
1217               nodeInd2  = nodeIndsOfFace[i].second;
1218             }
1219           }
1220           // not to visit rejected faces
1221           for ( size_t i = 0; i < facesNearLink.size(); ++i )
1222             if ( facesNearLink[i] != otherFace && theFaces.size() > 1 )
1223               visitedFaces.insert( facesNearLink[i] );
1224         }
1225         else if ( facesNearLink.size() == 1 )
1226         {
1227           otherFace = facesNearLink[0];
1228           nodeInd1  = nodeIndsOfFace.back().first;
1229           nodeInd2  = nodeIndsOfFace.back().second;
1230         }
1231         if ( otherFace && otherFace != theFace)
1232         {
1233           // link must be reverse in otherFace if orientation ot otherFace
1234           // is same as that of theFace
1235           if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
1236           {
1237             nbReori += Reorient( otherFace );
1238           }
1239           startFaces.insert( otherFace );
1240         }
1241       }
1242       std::swap( link.first, link.second ); // reverse the link
1243     }
1244   }
1245   return nbReori;
1246 }
1247
1248 //=======================================================================
1249 //function : getBadRate
1250 //purpose  :
1251 //=======================================================================
1252
1253 static double getBadRate (const SMDS_MeshElement*               theElem,
1254                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1255 {
1256   SMESH::Controls::TSequenceOfXYZ P;
1257   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1258     return 1e100;
1259   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1260   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1261 }
1262
1263 //=======================================================================
1264 //function : QuadToTri
1265 //purpose  : Cut quadrangles into triangles.
1266 //           theCrit is used to select a diagonal to cut
1267 //=======================================================================
1268
1269 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1270                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1271 {
1272   myLastCreatedElems.Clear();
1273   myLastCreatedNodes.Clear();
1274
1275   if ( !theCrit.get() )
1276     return false;
1277
1278   SMESHDS_Mesh * aMesh = GetMeshDS();
1279
1280   Handle(Geom_Surface) surface;
1281   SMESH_MesherHelper   helper( *GetMesh() );
1282
1283   TIDSortedElemSet::iterator itElem;
1284   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
1285   {
1286     const SMDS_MeshElement* elem = *itElem;
1287     if ( !elem || elem->GetType() != SMDSAbs_Face )
1288       continue;
1289     if ( elem->NbCornerNodes() != 4 )
1290       continue;
1291
1292     // retrieve element nodes
1293     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1294
1295     // compare two sets of possible triangles
1296     double aBadRate1, aBadRate2; // to what extent a set is bad
1297     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1298     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1299     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1300
1301     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1302     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1303     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1304
1305     const int aShapeId = FindShape( elem );
1306     const SMDS_MeshElement* newElem1 = 0;
1307     const SMDS_MeshElement* newElem2 = 0;
1308
1309     if ( !elem->IsQuadratic() ) // split liner quadrangle
1310     {
1311       // for MaxElementLength2D functor we return minimum diagonal for splitting,
1312       // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1313       if ( aBadRate1 <= aBadRate2 ) {
1314         // tr1 + tr2 is better
1315         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1316         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1317       }
1318       else {
1319         // tr3 + tr4 is better
1320         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1321         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1322       }
1323     }
1324     else // split quadratic quadrangle
1325     {
1326       helper.SetIsQuadratic( true );
1327       helper.SetIsBiQuadratic( aNodes.size() == 9 );
1328
1329       helper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem ));
1330       if ( aNodes.size() == 9 )
1331       {
1332         helper.SetIsBiQuadratic( true );
1333         if ( aBadRate1 <= aBadRate2 )
1334           helper.AddTLinkNode( aNodes[0], aNodes[2], aNodes[8] );
1335         else
1336           helper.AddTLinkNode( aNodes[1], aNodes[3], aNodes[8] );
1337       }
1338       // create a new element
1339       if ( aBadRate1 <= aBadRate2 ) {
1340         newElem1 = helper.AddFace( aNodes[2], aNodes[3], aNodes[0] );
1341         newElem2 = helper.AddFace( aNodes[2], aNodes[0], aNodes[1] );
1342       }
1343       else {
1344         newElem1 = helper.AddFace( aNodes[3], aNodes[0], aNodes[1] );
1345         newElem2 = helper.AddFace( aNodes[3], aNodes[1], aNodes[2] );
1346       }
1347     } // quadratic case
1348
1349     // care of a new element
1350
1351     myLastCreatedElems.Append(newElem1);
1352     myLastCreatedElems.Append(newElem2);
1353     AddToSameGroups( newElem1, elem, aMesh );
1354     AddToSameGroups( newElem2, elem, aMesh );
1355
1356     // put a new triangle on the same shape
1357     if ( aShapeId )
1358       aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1359     aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1360
1361     aMesh->RemoveElement( elem );
1362   }
1363   return true;
1364 }
1365
1366 //=======================================================================
1367 /*!
1368  * \brief Split each of given quadrangles into 4 triangles.
1369  * \param theElems - The faces to be splitted. If empty all faces are split.
1370  */
1371 //=======================================================================
1372
1373 void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
1374 {
1375   myLastCreatedElems.Clear();
1376   myLastCreatedNodes.Clear();
1377
1378   SMESH_MesherHelper helper( *GetMesh() );
1379   helper.SetElementsOnShape( true );
1380
1381   SMDS_ElemIteratorPtr faceIt;
1382   if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face);
1383   else                    faceIt = elemSetIterator( theElems );
1384
1385   bool   checkUV;
1386   gp_XY  uv [9]; uv[8] = gp_XY(0,0);
1387   gp_XYZ xyz[9];
1388   vector< const SMDS_MeshNode* > nodes;
1389   SMESHDS_SubMesh*               subMeshDS;
1390   TopoDS_Face                    F;
1391   Handle(Geom_Surface)           surface;
1392   TopLoc_Location                loc;
1393
1394   while ( faceIt->more() )
1395   {
1396     const SMDS_MeshElement* quad = faceIt->next();
1397     if ( !quad || quad->NbCornerNodes() != 4 )
1398       continue;
1399
1400     // get a surface the quad is on
1401
1402     if ( quad->getshapeId() < 1 )
1403     {
1404       F.Nullify();
1405       helper.SetSubShape( 0 );
1406       subMeshDS = 0;
1407     }
1408     else if ( quad->getshapeId() != helper.GetSubShapeID() )
1409     {
1410       helper.SetSubShape( quad->getshapeId() );
1411       if ( !helper.GetSubShape().IsNull() &&
1412            helper.GetSubShape().ShapeType() == TopAbs_FACE )
1413       {
1414         F = TopoDS::Face( helper.GetSubShape() );
1415         surface = BRep_Tool::Surface( F, loc );
1416         subMeshDS = GetMeshDS()->MeshElements( quad->getshapeId() );
1417       }
1418       else
1419       {
1420         helper.SetSubShape( 0 );
1421         subMeshDS = 0;
1422       }
1423     }
1424
1425     // create a central node
1426
1427     const SMDS_MeshNode* nCentral;
1428     nodes.assign( quad->begin_nodes(), quad->end_nodes() );
1429
1430     if ( nodes.size() == 9 )
1431     {
1432       nCentral = nodes.back();
1433     }
1434     else
1435     {
1436       size_t iN = 0;
1437       if ( F.IsNull() )
1438       {
1439         for ( ; iN < nodes.size(); ++iN )
1440           xyz[ iN ] = SMESH_TNodeXYZ( nodes[ iN ] );
1441
1442         for ( ; iN < 8; ++iN ) // mid-side points of a linear qudrangle
1443           xyz[ iN ] = 0.5 * ( xyz[ iN - 4 ] + xyz[( iN - 3 )%4 ] );
1444
1445         xyz[ 8 ] = helper.calcTFI( 0.5, 0.5,
1446                                    xyz[0], xyz[1], xyz[2], xyz[3],
1447                                    xyz[4], xyz[5], xyz[6], xyz[7] );
1448       }
1449       else
1450       {
1451         for ( ; iN < nodes.size(); ++iN )
1452           uv[ iN ] = helper.GetNodeUV( F, nodes[iN], nodes[(iN+2)%4], &checkUV );
1453
1454         for ( ; iN < 8; ++iN ) // UV of mid-side points of a linear qudrangle
1455           uv[ iN ] = helper.GetMiddleUV( surface, uv[ iN - 4 ], uv[( iN - 3 )%4 ] );
1456
1457         uv[ 8 ] = helper.calcTFI( 0.5, 0.5,
1458                                   uv[0], uv[1], uv[2], uv[3],
1459                                   uv[4], uv[5], uv[6], uv[7] );
1460
1461         gp_Pnt p = surface->Value( uv[8].X(), uv[8].Y() ).Transformed( loc );
1462         xyz[ 8 ] = p.XYZ();
1463       }
1464
1465       nCentral = helper.AddNode( xyz[8].X(), xyz[8].Y(), xyz[8].Z(), /*id=*/0,
1466                                  uv[8].X(), uv[8].Y() );
1467       myLastCreatedNodes.Append( nCentral );
1468     }
1469
1470     // create 4 triangles
1471
1472     GetMeshDS()->RemoveFreeElement( quad, subMeshDS, /*fromGroups=*/false );
1473     
1474     helper.SetIsQuadratic  ( nodes.size() > 4 );
1475     helper.SetIsBiQuadratic( nodes.size() == 9 );
1476     if ( helper.GetIsQuadratic() )
1477       helper.AddTLinks( static_cast< const SMDS_MeshFace*>( quad ));
1478
1479     for ( int i = 0; i < 4; ++i )
1480     {
1481       SMDS_MeshElement* tria = helper.AddFace( nodes[ i ],
1482                                                nodes[(i+1)%4],
1483                                                nCentral );
1484       ReplaceElemInGroups( tria, quad, GetMeshDS() );
1485       myLastCreatedElems.Append( tria );
1486     }
1487   }
1488 }
1489
1490 //=======================================================================
1491 //function : BestSplit
1492 //purpose  : Find better diagonal for cutting.
1493 //=======================================================================
1494
1495 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1496                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1497 {
1498   myLastCreatedElems.Clear();
1499   myLastCreatedNodes.Clear();
1500
1501   if (!theCrit.get())
1502     return -1;
1503
1504   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1505     return -1;
1506
1507   if( theQuad->NbNodes()==4 ||
1508       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1509
1510     // retrieve element nodes
1511     const SMDS_MeshNode* aNodes [4];
1512     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1513     int i = 0;
1514     //while (itN->more())
1515     while (i<4) {
1516       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1517     }
1518     // compare two sets of possible triangles
1519     double aBadRate1, aBadRate2; // to what extent a set is bad
1520     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1521     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1522     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1523
1524     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1525     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1526     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1527     // for MaxElementLength2D functor we return minimum diagonal for splitting,
1528     // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1529     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1530       return 1; // diagonal 1-3
1531
1532     return 2; // diagonal 2-4
1533   }
1534   return -1;
1535 }
1536
1537 namespace
1538 {
1539   // Methods of splitting volumes into tetra
1540
1541   const int theHexTo5_1[5*4+1] =
1542     {
1543       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1544     };
1545   const int theHexTo5_2[5*4+1] =
1546     {
1547       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1548     };
1549   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1550
1551   const int theHexTo6_1[6*4+1] =
1552     {
1553       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
1554     };
1555   const int theHexTo6_2[6*4+1] =
1556     {
1557       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
1558     };
1559   const int theHexTo6_3[6*4+1] =
1560     {
1561       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
1562     };
1563   const int theHexTo6_4[6*4+1] =
1564     {
1565       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
1566     };
1567   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1568
1569   const int thePyraTo2_1[2*4+1] =
1570     {
1571       0, 1, 2, 4,    0, 2, 3, 4,   -1
1572     };
1573   const int thePyraTo2_2[2*4+1] =
1574     {
1575       1, 2, 3, 4,    1, 3, 0, 4,   -1
1576     };
1577   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1578
1579   const int thePentaTo3_1[3*4+1] =
1580     {
1581       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1582     };
1583   const int thePentaTo3_2[3*4+1] =
1584     {
1585       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1586     };
1587   const int thePentaTo3_3[3*4+1] =
1588     {
1589       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1590     };
1591   const int thePentaTo3_4[3*4+1] =
1592     {
1593       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1594     };
1595   const int thePentaTo3_5[3*4+1] =
1596     {
1597       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1598     };
1599   const int thePentaTo3_6[3*4+1] =
1600     {
1601       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1602     };
1603   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1604                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1605
1606   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1607   {
1608     int _n1, _n2, _n3;
1609     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1610     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1611     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1612   };
1613   struct TSplitMethod
1614   {
1615     int        _nbTetra;
1616     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1617     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1618     bool       _ownConn;      //!< to delete _connectivity in destructor
1619     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1620
1621     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1622       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1623     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1624     bool hasFacet( const TTriangleFacet& facet ) const
1625     {
1626       const int* tetConn = _connectivity;
1627       for ( ; tetConn[0] >= 0; tetConn += 4 )
1628         if (( facet.contains( tetConn[0] ) +
1629               facet.contains( tetConn[1] ) +
1630               facet.contains( tetConn[2] ) +
1631               facet.contains( tetConn[3] )) == 3 )
1632           return true;
1633       return false;
1634     }
1635   };
1636
1637   //=======================================================================
1638   /*!
1639    * \brief return TSplitMethod for the given element
1640    */
1641   //=======================================================================
1642
1643   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1644   {
1645     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1646
1647     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1648     // an edge and a face barycenter; tertaherdons are based on triangles and
1649     // a volume barycenter
1650     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1651
1652     // Find out how adjacent volumes are split
1653
1654     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1655     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1656     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1657     {
1658       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1659       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1660       if ( nbNodes < 4 ) continue;
1661
1662       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1663       const int* nInd = vol.GetFaceNodesIndices( iF );
1664       if ( nbNodes == 4 )
1665       {
1666         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1667         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1668         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1669         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1670       }
1671       else
1672       {
1673         int iCom = 0; // common node of triangle faces to split into
1674         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1675         {
1676           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1677                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1678                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1679           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1680                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1681                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1682           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1683           {
1684             triaSplits.push_back( t012 );
1685             triaSplits.push_back( t023 );
1686             break;
1687           }
1688         }
1689       }
1690       if ( !triaSplits.empty() )
1691         hasAdjacentSplits = true;
1692     }
1693
1694     // Among variants of split method select one compliant with adjacent volumes
1695
1696     TSplitMethod method;
1697     if ( !vol.Element()->IsPoly() && !is24TetMode )
1698     {
1699       int nbVariants = 2, nbTet = 0;
1700       const int** connVariants = 0;
1701       switch ( vol.Element()->GetEntityType() )
1702       {
1703       case SMDSEntity_Hexa:
1704       case SMDSEntity_Quad_Hexa:
1705       case SMDSEntity_TriQuad_Hexa:
1706         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1707           connVariants = theHexTo5, nbTet = 5;
1708         else
1709           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1710         break;
1711       case SMDSEntity_Pyramid:
1712       case SMDSEntity_Quad_Pyramid:
1713         connVariants = thePyraTo2;  nbTet = 2;
1714         break;
1715       case SMDSEntity_Penta:
1716       case SMDSEntity_Quad_Penta:
1717         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1718         break;
1719       default:
1720         nbVariants = 0;
1721       }
1722       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1723       {
1724         // check method compliancy with adjacent tetras,
1725         // all found splits must be among facets of tetras described by this method
1726         method = TSplitMethod( nbTet, connVariants[variant] );
1727         if ( hasAdjacentSplits && method._nbTetra > 0 )
1728         {
1729           bool facetCreated = true;
1730           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1731           {
1732             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1733             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1734               facetCreated = method.hasFacet( *facet );
1735           }
1736           if ( !facetCreated )
1737             method = TSplitMethod(0); // incompatible method
1738         }
1739       }
1740     }
1741     if ( method._nbTetra < 1 )
1742     {
1743       // No standard method is applicable, use a generic solution:
1744       // each facet of a volume is split into triangles and
1745       // each of triangles and a volume barycenter form a tetrahedron.
1746
1747       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1748
1749       int* connectivity = new int[ maxTetConnSize + 1 ];
1750       method._connectivity = connectivity;
1751       method._ownConn = true;
1752       method._baryNode = !isHex27; // to create central node or not
1753
1754       int connSize = 0;
1755       int baryCenInd = vol.NbNodes() - int( isHex27 );
1756       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1757       {
1758         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1759         const int*   nInd = vol.GetFaceNodesIndices( iF );
1760         // find common node of triangle facets of tetra to create
1761         int iCommon = 0; // index in linear numeration
1762         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1763         if ( !triaSplits.empty() )
1764         {
1765           // by found facets
1766           const TTriangleFacet* facet = &triaSplits.front();
1767           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1768             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1769                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1770               break;
1771         }
1772         else if ( nbNodes > 3 && !is24TetMode )
1773         {
1774           // find the best method of splitting into triangles by aspect ratio
1775           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1776           map< double, int > badness2iCommon;
1777           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1778           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1779           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1780           {
1781             double badness = 0;
1782             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1783             {
1784               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1785                                       nodes[ iQ*((iLast-1)%nbNodes)],
1786                                       nodes[ iQ*((iLast  )%nbNodes)]);
1787               badness += getBadRate( &tria, aspectRatio );
1788             }
1789             badness2iCommon.insert( make_pair( badness, iCommon ));
1790           }
1791           // use iCommon with lowest badness
1792           iCommon = badness2iCommon.begin()->second;
1793         }
1794         if ( iCommon >= nbNodes )
1795           iCommon = 0; // something wrong
1796
1797         // fill connectivity of tetrahedra based on a current face
1798         int nbTet = nbNodes - 2;
1799         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1800         {
1801           int faceBaryCenInd;
1802           if ( isHex27 )
1803           {
1804             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
1805             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
1806           }
1807           else
1808           {
1809             method._faceBaryNode[ iF ] = 0;
1810             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1811           }
1812           nbTet = nbNodes;
1813           for ( int i = 0; i < nbTet; ++i )
1814           {
1815             int i1 = i, i2 = (i+1) % nbNodes;
1816             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1817             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1818             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1819             connectivity[ connSize++ ] = faceBaryCenInd;
1820             connectivity[ connSize++ ] = baryCenInd;
1821           }
1822         }
1823         else
1824         {
1825           for ( int i = 0; i < nbTet; ++i )
1826           {
1827             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1828             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1829             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1830             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1831             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1832             connectivity[ connSize++ ] = baryCenInd;
1833           }
1834         }
1835         method._nbTetra += nbTet;
1836
1837       } // loop on volume faces
1838
1839       connectivity[ connSize++ ] = -1;
1840
1841     } // end of generic solution
1842
1843     return method;
1844   }
1845   //================================================================================
1846   /*!
1847    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1848    */
1849   //================================================================================
1850
1851   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1852   {
1853     // find the tetrahedron including the three nodes of facet
1854     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1855     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1856     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1857     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1858     while ( volIt1->more() )
1859     {
1860       const SMDS_MeshElement* v = volIt1->next();
1861       SMDSAbs_EntityType type = v->GetEntityType();
1862       if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
1863         continue;
1864       if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
1865         continue; // medium node not allowed
1866       const int ind2 = v->GetNodeIndex( n2 );
1867       if ( ind2 < 0 || 3 < ind2 )
1868         continue;
1869       const int ind3 = v->GetNodeIndex( n3 );
1870       if ( ind3 < 0 || 3 < ind3 )
1871         continue;
1872       return true;
1873     }
1874     return false;
1875   }
1876
1877   //=======================================================================
1878   /*!
1879    * \brief A key of a face of volume
1880    */
1881   //=======================================================================
1882
1883   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
1884   {
1885     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1886     {
1887       TIDSortedNodeSet sortedNodes;
1888       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1889       int nbNodes = vol.NbFaceNodes( iF );
1890       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1891       for ( int i = 0; i < nbNodes; i += iQ )
1892         sortedNodes.insert( fNodes[i] );
1893       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1894       first.first   = (*(n++))->GetID();
1895       first.second  = (*(n++))->GetID();
1896       second.first  = (*(n++))->GetID();
1897       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
1898     }
1899   };
1900 } // namespace
1901
1902 class TElemToDelete
1903 {
1904 public:
1905   TElemToDelete(const SMDS_MeshElement* theElem, SMESHDS_SubMesh* theSubMesh)
1906   {
1907     elem = theElem;
1908     subMesh = theSubMesh;
1909   }
1910   const SMDS_MeshElement* Elem() const {return elem;}
1911   SMESHDS_SubMesh* Submesh() {return subMesh;}
1912   const SMDS_MeshElement* elem;
1913   SMESHDS_SubMesh* subMesh;
1914 };
1915
1916 //=======================================================================
1917 //function : SplitVolumesIntoTetra
1918 //purpose  : Split volume elements into tetrahedra.
1919 //=======================================================================
1920
1921 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1922                                               const int                theMethodFlags)
1923 {
1924   // std-like iterator on coordinates of nodes of mesh element
1925   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1926   NXyzIterator xyzEnd;
1927
1928   SMDS_VolumeTool    volTool;
1929   SMESH_MesherHelper helper( *GetMesh());
1930
1931   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1932   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1933
1934   SMESH_SequenceOfElemPtr newNodes, newElems;
1935
1936   // map face of volume to it's baricenrtic node
1937   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1938   double bc[3];
1939
1940   TIDSortedElemSet::const_iterator elem = theElems.begin();
1941   std::vector<TElemToDelete> elem_to_delete;
1942   for ( ; elem != theElems.end(); ++elem )
1943   {
1944     if ( (*elem)->GetType() != SMDSAbs_Volume )
1945       continue;
1946     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1947     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
1948       continue;
1949
1950     if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
1951
1952     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1953     if ( splitMethod._nbTetra < 1 ) continue;
1954
1955     // find submesh to add new tetras to
1956     if ( !subMesh || !subMesh->Contains( *elem ))
1957     {
1958       int shapeID = FindShape( *elem );
1959       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1960       subMesh = GetMeshDS()->MeshElements( shapeID );
1961     }
1962     int iQ;
1963     if ( (*elem)->IsQuadratic() )
1964     {
1965       iQ = 2;
1966       // add quadratic links to the helper
1967       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1968       {
1969         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1970         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
1971         for ( int iN = 0; iN < nbN; iN += iQ )
1972           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
1973       }
1974       helper.SetIsQuadratic( true );
1975     }
1976     else
1977     {
1978       iQ = 1;
1979       helper.SetIsQuadratic( false );
1980     }
1981     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1982     helper.SetElementsOnShape( true );
1983     if ( splitMethod._baryNode )
1984     {
1985       // make a node at barycenter
1986       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1987       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1988       nodes.push_back( gcNode );
1989       newNodes.Append( gcNode );
1990     }
1991     if ( !splitMethod._faceBaryNode.empty() )
1992     {
1993       // make or find baricentric nodes of faces
1994       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1995       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1996       {
1997         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1998           volFace2BaryNode.insert
1999           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
2000         if ( !f_n->second )
2001         {
2002           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
2003           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
2004         }
2005         nodes.push_back( iF_n->second = f_n->second );
2006       }
2007     }
2008
2009     // make tetras
2010     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
2011     const int* tetConn = splitMethod._connectivity;
2012     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
2013       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
2014                                                        nodes[ tetConn[1] ],
2015                                                        nodes[ tetConn[2] ],
2016                                                        nodes[ tetConn[3] ]));
2017
2018     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
2019
2020     // Split faces on sides of the split volume
2021
2022     const SMDS_MeshNode** volNodes = volTool.GetNodes();
2023     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
2024     {
2025       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
2026       if ( nbNodes < 4 ) continue;
2027
2028       // find an existing face
2029       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
2030                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
2031       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
2032                                                                        /*noMedium=*/false))
2033       {
2034         // make triangles
2035         helper.SetElementsOnShape( false );
2036         vector< const SMDS_MeshElement* > triangles;
2037
2038         // find submesh to add new triangles in
2039         if ( !fSubMesh || !fSubMesh->Contains( face ))
2040         {
2041           int shapeID = FindShape( face );
2042           fSubMesh = GetMeshDS()->MeshElements( shapeID );
2043         }
2044         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
2045         if ( iF_n != splitMethod._faceBaryNode.end() )
2046         {
2047           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
2048           {
2049             const SMDS_MeshNode* n1 = fNodes[iN];
2050             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
2051             const SMDS_MeshNode *n3 = iF_n->second;
2052             if ( !volTool.IsFaceExternal( iF ))
2053               swap( n2, n3 );
2054             triangles.push_back( helper.AddFace( n1,n2,n3 ));
2055
2056             if ( fSubMesh && n3->getshapeId() < 1 )
2057               fSubMesh->AddNode( n3 );
2058           }
2059         }
2060         else
2061         {
2062           // among possible triangles create ones discribed by split method
2063           const int* nInd = volTool.GetFaceNodesIndices( iF );
2064           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
2065           int iCom = 0; // common node of triangle faces to split into
2066           list< TTriangleFacet > facets;
2067           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
2068           {
2069             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
2070                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
2071                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
2072             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
2073                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
2074                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
2075             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
2076             {
2077               facets.push_back( t012 );
2078               facets.push_back( t023 );
2079               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
2080                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
2081                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
2082                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
2083               break;
2084             }
2085           }
2086           list< TTriangleFacet >::iterator facet = facets.begin();
2087           for ( ; facet != facets.end(); ++facet )
2088           {
2089             if ( !volTool.IsFaceExternal( iF ))
2090               swap( facet->_n2, facet->_n3 );
2091             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
2092                                                  volNodes[ facet->_n2 ],
2093                                                  volNodes[ facet->_n3 ]));
2094           }
2095         }
2096         for ( int i = 0; i < triangles.size(); ++i )
2097         {
2098           if ( !triangles[i] ) continue;
2099           if ( fSubMesh )
2100             fSubMesh->AddElement( triangles[i]);
2101           newElems.Append( triangles[i] );
2102         }
2103         ReplaceElemInGroups( face, triangles, GetMeshDS() );
2104         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
2105 //         TElemToDelete faceToDelete(face, fSubMesh);
2106 //         elem_to_delete.push_back(faceToDelete); 
2107       }
2108
2109     } // loop on volume faces to split them into triangles
2110
2111 //     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
2112
2113     // rnc : don't delete the elem here because it results in a mesh with a free
2114     // ID at the beginning of the ID list. The first tetra is then inserted in O(1)
2115     // but the second one is inserted in O(n), then the whole procedure has almost a O(n^2)
2116     // complexity. If all elements to remove are stored and removed after tetra creation 
2117     // we get a O(n) complexity for the whole procedure. 
2118     // The memory cost is at worst a 6*n*constant memory occupation (where n is the number of elements) 
2119     // before deletion of the hexas and then 5*n*constant instead of a maximum of 5*n*constant.
2120     // So there is a transient 1/5*(memory occupation) additional cost.
2121
2122     // Store the elements to delete
2123     TElemToDelete elemToDelete(*elem, subMesh);
2124     elem_to_delete.push_back(elemToDelete);
2125
2126     if ( geomType == SMDSEntity_TriQuad_Hexa )
2127     {
2128       // remove medium nodes that could become free
2129       for ( int i = 20; i < volTool.NbNodes(); ++i )
2130         if ( volNodes[i]->NbInverseElements() == 0 )
2131           GetMeshDS()->RemoveNode( volNodes[i] );
2132     }
2133   } // loop on volumes to split
2134
2135   // Delete stored elements
2136   std::vector<TElemToDelete>::iterator it;
2137   for( it = elem_to_delete.begin(); it!= elem_to_delete.end(); it++)
2138   {
2139     GetMeshDS()->RemoveFreeElement( it->Elem(), it->Submesh(), /*fromGroups=*/false );
2140   }
2141   
2142   myLastCreatedNodes = newNodes;
2143   myLastCreatedElems = newElems;
2144 }
2145
2146 //=======================================================================
2147 //function : AddToSameGroups
2148 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
2149 //=======================================================================
2150
2151 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
2152                                         const SMDS_MeshElement* elemInGroups,
2153                                         SMESHDS_Mesh *          aMesh)
2154 {
2155   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2156   if (!groups.empty()) {
2157     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2158     for ( ; grIt != groups.end(); grIt++ ) {
2159       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2160       if ( group && group->Contains( elemInGroups ))
2161         group->SMDSGroup().Add( elemToAdd );
2162     }
2163   }
2164 }
2165
2166
2167 //=======================================================================
2168 //function : RemoveElemFromGroups
2169 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
2170 //=======================================================================
2171 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
2172                                              SMESHDS_Mesh *          aMesh)
2173 {
2174   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2175   if (!groups.empty())
2176   {
2177     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
2178     for (; GrIt != groups.end(); GrIt++)
2179     {
2180       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
2181       if (!grp || grp->IsEmpty()) continue;
2182       grp->SMDSGroup().Remove(removeelem);
2183     }
2184   }
2185 }
2186
2187 //================================================================================
2188 /*!
2189  * \brief Replace elemToRm by elemToAdd in the all groups
2190  */
2191 //================================================================================
2192
2193 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
2194                                             const SMDS_MeshElement* elemToAdd,
2195                                             SMESHDS_Mesh *          aMesh)
2196 {
2197   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2198   if (!groups.empty()) {
2199     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2200     for ( ; grIt != groups.end(); grIt++ ) {
2201       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2202       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
2203         group->SMDSGroup().Add( elemToAdd );
2204     }
2205   }
2206 }
2207
2208 //================================================================================
2209 /*!
2210  * \brief Replace elemToRm by elemToAdd in the all groups
2211  */
2212 //================================================================================
2213
2214 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
2215                                             const vector<const SMDS_MeshElement*>& elemToAdd,
2216                                             SMESHDS_Mesh *                         aMesh)
2217 {
2218   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2219   if (!groups.empty())
2220   {
2221     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2222     for ( ; grIt != groups.end(); grIt++ ) {
2223       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2224       if ( group && group->SMDSGroup().Remove( elemToRm ) )
2225         for ( int i = 0; i < elemToAdd.size(); ++i )
2226           group->SMDSGroup().Add( elemToAdd[ i ] );
2227     }
2228   }
2229 }
2230
2231 //=======================================================================
2232 //function : QuadToTri
2233 //purpose  : Cut quadrangles into triangles.
2234 //           theCrit is used to select a diagonal to cut
2235 //=======================================================================
2236
2237 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
2238                                   const bool         the13Diag)
2239 {
2240   myLastCreatedElems.Clear();
2241   myLastCreatedNodes.Clear();
2242
2243   MESSAGE( "::QuadToTri()" );
2244
2245   SMESHDS_Mesh * aMesh = GetMeshDS();
2246
2247   Handle(Geom_Surface) surface;
2248   SMESH_MesherHelper   helper( *GetMesh() );
2249
2250   TIDSortedElemSet::iterator itElem;
2251   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2252     const SMDS_MeshElement* elem = *itElem;
2253     if ( !elem || elem->GetType() != SMDSAbs_Face )
2254       continue;
2255     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
2256     if(!isquad) continue;
2257
2258     if(elem->NbNodes()==4) {
2259       // retrieve element nodes
2260       const SMDS_MeshNode* aNodes [4];
2261       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2262       int i = 0;
2263       while ( itN->more() )
2264         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2265
2266       int aShapeId = FindShape( elem );
2267       const SMDS_MeshElement* newElem1 = 0;
2268       const SMDS_MeshElement* newElem2 = 0;
2269       if ( the13Diag ) {
2270         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
2271         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
2272       }
2273       else {
2274         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
2275         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
2276       }
2277       myLastCreatedElems.Append(newElem1);
2278       myLastCreatedElems.Append(newElem2);
2279       // put a new triangle on the same shape and add to the same groups
2280       if ( aShapeId )
2281         {
2282           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2283           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2284         }
2285       AddToSameGroups( newElem1, elem, aMesh );
2286       AddToSameGroups( newElem2, elem, aMesh );
2287       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
2288       aMesh->RemoveElement( elem );
2289     }
2290
2291     // Quadratic quadrangle
2292
2293     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
2294
2295       // get surface elem is on
2296       int aShapeId = FindShape( elem );
2297       if ( aShapeId != helper.GetSubShapeID() ) {
2298         surface.Nullify();
2299         TopoDS_Shape shape;
2300         if ( aShapeId > 0 )
2301           shape = aMesh->IndexToShape( aShapeId );
2302         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
2303           TopoDS_Face face = TopoDS::Face( shape );
2304           surface = BRep_Tool::Surface( face );
2305           if ( !surface.IsNull() )
2306             helper.SetSubShape( shape );
2307         }
2308       }
2309
2310       const SMDS_MeshNode* aNodes [8];
2311       const SMDS_MeshNode* inFaceNode = 0;
2312       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2313       int i = 0;
2314       while ( itN->more() ) {
2315         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2316         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
2317              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
2318         {
2319           inFaceNode = aNodes[ i-1 ];
2320         }
2321       }
2322
2323       // find middle point for (0,1,2,3)
2324       // and create a node in this point;
2325       gp_XYZ p( 0,0,0 );
2326       if ( surface.IsNull() ) {
2327         for(i=0; i<4; i++)
2328           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
2329         p /= 4;
2330       }
2331       else {
2332         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
2333         gp_XY uv( 0,0 );
2334         for(i=0; i<4; i++)
2335           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
2336         uv /= 4.;
2337         p = surface->Value( uv.X(), uv.Y() ).XYZ();
2338       }
2339       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
2340       myLastCreatedNodes.Append(newN);
2341
2342       // create a new element
2343       const SMDS_MeshElement* newElem1 = 0;
2344       const SMDS_MeshElement* newElem2 = 0;
2345       if ( the13Diag ) {
2346         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
2347                                   aNodes[6], aNodes[7], newN );
2348         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
2349                                   newN,      aNodes[4], aNodes[5] );
2350       }
2351       else {
2352         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
2353                                   aNodes[7], aNodes[4], newN );
2354         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
2355                                   newN,      aNodes[5], aNodes[6] );
2356       }
2357       myLastCreatedElems.Append(newElem1);
2358       myLastCreatedElems.Append(newElem2);
2359       // put a new triangle on the same shape and add to the same groups
2360       if ( aShapeId )
2361         {
2362           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2363           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2364         }
2365       AddToSameGroups( newElem1, elem, aMesh );
2366       AddToSameGroups( newElem2, elem, aMesh );
2367       aMesh->RemoveElement( elem );
2368     }
2369   }
2370
2371   return true;
2372 }
2373
2374 //=======================================================================
2375 //function : getAngle
2376 //purpose  :
2377 //=======================================================================
2378
2379 double getAngle(const SMDS_MeshElement * tr1,
2380                 const SMDS_MeshElement * tr2,
2381                 const SMDS_MeshNode *    n1,
2382                 const SMDS_MeshNode *    n2)
2383 {
2384   double angle = 2. * M_PI; // bad angle
2385
2386   // get normals
2387   SMESH::Controls::TSequenceOfXYZ P1, P2;
2388   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2389        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2390     return angle;
2391   gp_Vec N1,N2;
2392   if(!tr1->IsQuadratic())
2393     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2394   else
2395     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2396   if ( N1.SquareMagnitude() <= gp::Resolution() )
2397     return angle;
2398   if(!tr2->IsQuadratic())
2399     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2400   else
2401     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2402   if ( N2.SquareMagnitude() <= gp::Resolution() )
2403     return angle;
2404
2405   // find the first diagonal node n1 in the triangles:
2406   // take in account a diagonal link orientation
2407   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2408   for ( int t = 0; t < 2; t++ ) {
2409     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2410     int i = 0, iDiag = -1;
2411     while ( it->more()) {
2412       const SMDS_MeshElement *n = it->next();
2413       if ( n == n1 || n == n2 ) {
2414         if ( iDiag < 0)
2415           iDiag = i;
2416         else {
2417           if ( i - iDiag == 1 )
2418             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2419           else
2420             nFirst[ t ] = n;
2421           break;
2422         }
2423       }
2424       i++;
2425     }
2426   }
2427   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2428     N2.Reverse();
2429
2430   angle = N1.Angle( N2 );
2431   //SCRUTE( angle );
2432   return angle;
2433 }
2434
2435 // =================================================
2436 // class generating a unique ID for a pair of nodes
2437 // and able to return nodes by that ID
2438 // =================================================
2439 class LinkID_Gen {
2440 public:
2441
2442   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2443     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2444   {}
2445
2446   long GetLinkID (const SMDS_MeshNode * n1,
2447                   const SMDS_MeshNode * n2) const
2448   {
2449     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2450   }
2451
2452   bool GetNodes (const long             theLinkID,
2453                  const SMDS_MeshNode* & theNode1,
2454                  const SMDS_MeshNode* & theNode2) const
2455   {
2456     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2457     if ( !theNode1 ) return false;
2458     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2459     if ( !theNode2 ) return false;
2460     return true;
2461   }
2462
2463 private:
2464   LinkID_Gen();
2465   const SMESHDS_Mesh* myMesh;
2466   long                myMaxID;
2467 };
2468
2469
2470 //=======================================================================
2471 //function : TriToQuad
2472 //purpose  : Fuse neighbour triangles into quadrangles.
2473 //           theCrit is used to select a neighbour to fuse with.
2474 //           theMaxAngle is a max angle between element normals at which
2475 //           fusion is still performed.
2476 //=======================================================================
2477
2478 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2479                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2480                                   const double                         theMaxAngle)
2481 {
2482   myLastCreatedElems.Clear();
2483   myLastCreatedNodes.Clear();
2484
2485   MESSAGE( "::TriToQuad()" );
2486
2487   if ( !theCrit.get() )
2488     return false;
2489
2490   SMESHDS_Mesh * aMesh = GetMeshDS();
2491
2492   // Prepare data for algo: build
2493   // 1. map of elements with their linkIDs
2494   // 2. map of linkIDs with their elements
2495
2496   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2497   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2498   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2499   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2500
2501   TIDSortedElemSet::iterator itElem;
2502   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
2503   {
2504     const SMDS_MeshElement* elem = *itElem;
2505     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2506     bool IsTria = ( elem->NbCornerNodes()==3 );
2507     if (!IsTria) continue;
2508
2509     // retrieve element nodes
2510     const SMDS_MeshNode* aNodes [4];
2511     SMDS_NodeIteratorPtr itN = elem->nodeIterator();
2512     int i = 0;
2513     while ( i < 3 )
2514       aNodes[ i++ ] = itN->next();
2515     aNodes[ 3 ] = aNodes[ 0 ];
2516
2517     // fill maps
2518     for ( i = 0; i < 3; i++ ) {
2519       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2520       // check if elements sharing a link can be fused
2521       itLE = mapLi_listEl.find( link );
2522       if ( itLE != mapLi_listEl.end() ) {
2523         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2524           continue;
2525         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2526         //if ( FindShape( elem ) != FindShape( elem2 ))
2527         //  continue; // do not fuse triangles laying on different shapes
2528         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2529           continue; // avoid making badly shaped quads
2530         (*itLE).second.push_back( elem );
2531       }
2532       else {
2533         mapLi_listEl[ link ].push_back( elem );
2534       }
2535       mapEl_setLi [ elem ].insert( link );
2536     }
2537   }
2538   // Clean the maps from the links shared by a sole element, ie
2539   // links to which only one element is bound in mapLi_listEl
2540
2541   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2542     int nbElems = (*itLE).second.size();
2543     if ( nbElems < 2  ) {
2544       const SMDS_MeshElement* elem = (*itLE).second.front();
2545       SMESH_TLink link = (*itLE).first;
2546       mapEl_setLi[ elem ].erase( link );
2547       if ( mapEl_setLi[ elem ].empty() )
2548         mapEl_setLi.erase( elem );
2549     }
2550   }
2551
2552   // Algo: fuse triangles into quadrangles
2553
2554   while ( ! mapEl_setLi.empty() ) {
2555     // Look for the start element:
2556     // the element having the least nb of shared links
2557     const SMDS_MeshElement* startElem = 0;
2558     int minNbLinks = 4;
2559     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2560       int nbLinks = (*itEL).second.size();
2561       if ( nbLinks < minNbLinks ) {
2562         startElem = (*itEL).first;
2563         minNbLinks = nbLinks;
2564         if ( minNbLinks == 1 )
2565           break;
2566       }
2567     }
2568
2569     // search elements to fuse starting from startElem or links of elements
2570     // fused earlyer - startLinks
2571     list< SMESH_TLink > startLinks;
2572     while ( startElem || !startLinks.empty() ) {
2573       while ( !startElem && !startLinks.empty() ) {
2574         // Get an element to start, by a link
2575         SMESH_TLink linkId = startLinks.front();
2576         startLinks.pop_front();
2577         itLE = mapLi_listEl.find( linkId );
2578         if ( itLE != mapLi_listEl.end() ) {
2579           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2580           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2581           for ( ; itE != listElem.end() ; itE++ )
2582             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2583               startElem = (*itE);
2584           mapLi_listEl.erase( itLE );
2585         }
2586       }
2587
2588       if ( startElem ) {
2589         // Get candidates to be fused
2590         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2591         const SMESH_TLink *link12, *link13;
2592         startElem = 0;
2593         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2594         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2595         ASSERT( !setLi.empty() );
2596         set< SMESH_TLink >::iterator itLi;
2597         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2598         {
2599           const SMESH_TLink & link = (*itLi);
2600           itLE = mapLi_listEl.find( link );
2601           if ( itLE == mapLi_listEl.end() )
2602             continue;
2603
2604           const SMDS_MeshElement* elem = (*itLE).second.front();
2605           if ( elem == tr1 )
2606             elem = (*itLE).second.back();
2607           mapLi_listEl.erase( itLE );
2608           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2609             continue;
2610           if ( tr2 ) {
2611             tr3 = elem;
2612             link13 = &link;
2613           }
2614           else {
2615             tr2 = elem;
2616             link12 = &link;
2617           }
2618
2619           // add other links of elem to list of links to re-start from
2620           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2621           set< SMESH_TLink >::iterator it;
2622           for ( it = links.begin(); it != links.end(); it++ ) {
2623             const SMESH_TLink& link2 = (*it);
2624             if ( link2 != link )
2625               startLinks.push_back( link2 );
2626           }
2627         }
2628
2629         // Get nodes of possible quadrangles
2630         const SMDS_MeshNode *n12 [4], *n13 [4];
2631         bool Ok12 = false, Ok13 = false;
2632         const SMDS_MeshNode *linkNode1, *linkNode2;
2633         if(tr2) {
2634           linkNode1 = link12->first;
2635           linkNode2 = link12->second;
2636           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2637             Ok12 = true;
2638         }
2639         if(tr3) {
2640           linkNode1 = link13->first;
2641           linkNode2 = link13->second;
2642           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2643             Ok13 = true;
2644         }
2645
2646         // Choose a pair to fuse
2647         if ( Ok12 && Ok13 ) {
2648           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2649           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2650           double aBadRate12 = getBadRate( &quad12, theCrit );
2651           double aBadRate13 = getBadRate( &quad13, theCrit );
2652           if (  aBadRate13 < aBadRate12 )
2653             Ok12 = false;
2654           else
2655             Ok13 = false;
2656         }
2657
2658         // Make quadrangles
2659         // and remove fused elems and remove links from the maps
2660         mapEl_setLi.erase( tr1 );
2661         if ( Ok12 )
2662         {
2663           mapEl_setLi.erase( tr2 );
2664           mapLi_listEl.erase( *link12 );
2665           if ( tr1->NbNodes() == 3 )
2666           {
2667             const SMDS_MeshElement* newElem = 0;
2668             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2669             myLastCreatedElems.Append(newElem);
2670             AddToSameGroups( newElem, tr1, aMesh );
2671             int aShapeId = tr1->getshapeId();
2672             if ( aShapeId )
2673               aMesh->SetMeshElementOnShape( newElem, aShapeId );
2674             aMesh->RemoveElement( tr1 );
2675             aMesh->RemoveElement( tr2 );
2676           }
2677           else {
2678             vector< const SMDS_MeshNode* > N1;
2679             vector< const SMDS_MeshNode* > N2;
2680             getNodesFromTwoTria(tr1,tr2,N1,N2);
2681             // now we receive following N1 and N2 (using numeration as in image in InverseDiag())
2682             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2683             // i.e. first nodes from both arrays form a new diagonal
2684             const SMDS_MeshNode* aNodes[8];
2685             aNodes[0] = N1[0];
2686             aNodes[1] = N1[1];
2687             aNodes[2] = N2[0];
2688             aNodes[3] = N2[1];
2689             aNodes[4] = N1[3];
2690             aNodes[5] = N2[5];
2691             aNodes[6] = N2[3];
2692             aNodes[7] = N1[5];
2693             const SMDS_MeshElement* newElem = 0;
2694             if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
2695               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2696                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
2697             else
2698               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2699                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2700             myLastCreatedElems.Append(newElem);
2701             AddToSameGroups( newElem, tr1, aMesh );
2702             int aShapeId = tr1->getshapeId();
2703             if ( aShapeId )
2704               aMesh->SetMeshElementOnShape( newElem, aShapeId );
2705             aMesh->RemoveElement( tr1 );
2706             aMesh->RemoveElement( tr2 );
2707             // remove middle node (9)
2708             if ( N1[4]->NbInverseElements() == 0 )
2709               aMesh->RemoveNode( N1[4] );
2710             if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
2711               aMesh->RemoveNode( N1[6] );
2712             if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
2713               aMesh->RemoveNode( N2[6] );
2714           }
2715         }
2716         else if ( Ok13 )
2717         {
2718           mapEl_setLi.erase( tr3 );
2719           mapLi_listEl.erase( *link13 );
2720           if ( tr1->NbNodes() == 3 ) {
2721             const SMDS_MeshElement* newElem = 0;
2722             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2723             myLastCreatedElems.Append(newElem);
2724             AddToSameGroups( newElem, tr1, aMesh );
2725             int aShapeId = tr1->getshapeId();
2726             if ( aShapeId )
2727               aMesh->SetMeshElementOnShape( newElem, aShapeId );
2728             aMesh->RemoveElement( tr1 );
2729             aMesh->RemoveElement( tr3 );
2730           }
2731           else {
2732             vector< const SMDS_MeshNode* > N1;
2733             vector< const SMDS_MeshNode* > N2;
2734             getNodesFromTwoTria(tr1,tr3,N1,N2);
2735             // now we receive following N1 and N2 (using numeration as above image)
2736             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2737             // i.e. first nodes from both arrays form a new diagonal
2738             const SMDS_MeshNode* aNodes[8];
2739             aNodes[0] = N1[0];
2740             aNodes[1] = N1[1];
2741             aNodes[2] = N2[0];
2742             aNodes[3] = N2[1];
2743             aNodes[4] = N1[3];
2744             aNodes[5] = N2[5];
2745             aNodes[6] = N2[3];
2746             aNodes[7] = N1[5];
2747             const SMDS_MeshElement* newElem = 0;
2748             if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
2749               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2750                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
2751             else
2752               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2753                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2754             myLastCreatedElems.Append(newElem);
2755             AddToSameGroups( newElem, tr1, aMesh );
2756             int aShapeId = tr1->getshapeId();
2757             if ( aShapeId )
2758               aMesh->SetMeshElementOnShape( newElem, aShapeId );
2759             aMesh->RemoveElement( tr1 );
2760             aMesh->RemoveElement( tr3 );
2761             // remove middle node (9)
2762             if ( N1[4]->NbInverseElements() == 0 )
2763               aMesh->RemoveNode( N1[4] );
2764             if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
2765               aMesh->RemoveNode( N1[6] );
2766             if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
2767               aMesh->RemoveNode( N2[6] );
2768           }
2769         }
2770
2771         // Next element to fuse: the rejected one
2772         if ( tr3 )
2773           startElem = Ok12 ? tr3 : tr2;
2774
2775       } // if ( startElem )
2776     } // while ( startElem || !startLinks.empty() )
2777   } // while ( ! mapEl_setLi.empty() )
2778
2779   return true;
2780 }
2781
2782
2783 /*#define DUMPSO(txt) \
2784 //  cout << txt << endl;
2785 //=============================================================================
2786 //
2787 //
2788 //
2789 //=============================================================================
2790 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2791 {
2792 if ( i1 == i2 )
2793 return;
2794 int tmp = idNodes[ i1 ];
2795 idNodes[ i1 ] = idNodes[ i2 ];
2796 idNodes[ i2 ] = tmp;
2797 gp_Pnt Ptmp = P[ i1 ];
2798 P[ i1 ] = P[ i2 ];
2799 P[ i2 ] = Ptmp;
2800 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2801 }
2802
2803 //=======================================================================
2804 //function : SortQuadNodes
2805 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2806 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2807 //           1 or 2 else 0.
2808 //=======================================================================
2809
2810 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2811 int               idNodes[] )
2812 {
2813   gp_Pnt P[4];
2814   int i;
2815   for ( i = 0; i < 4; i++ ) {
2816     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2817     if ( !n ) return 0;
2818     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2819   }
2820
2821   gp_Vec V1(P[0], P[1]);
2822   gp_Vec V2(P[0], P[2]);
2823   gp_Vec V3(P[0], P[3]);
2824
2825   gp_Vec Cross1 = V1 ^ V2;
2826   gp_Vec Cross2 = V2 ^ V3;
2827
2828   i = 0;
2829   if (Cross1.Dot(Cross2) < 0)
2830   {
2831     Cross1 = V2 ^ V1;
2832     Cross2 = V1 ^ V3;
2833
2834     if (Cross1.Dot(Cross2) < 0)
2835       i = 2;
2836     else
2837       i = 1;
2838     swap ( i, i + 1, idNodes, P );
2839
2840     //     for ( int ii = 0; ii < 4; ii++ ) {
2841     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2842     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2843     //     }
2844   }
2845   return i;
2846 }
2847
2848 //=======================================================================
2849 //function : SortHexaNodes
2850 //purpose  : Set 8 nodes of a hexahedron in a good order.
2851 //           Return success status
2852 //=======================================================================
2853
2854 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2855                                       int               idNodes[] )
2856 {
2857   gp_Pnt P[8];
2858   int i;
2859   DUMPSO( "INPUT: ========================================");
2860   for ( i = 0; i < 8; i++ ) {
2861     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2862     if ( !n ) return false;
2863     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2864     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2865   }
2866   DUMPSO( "========================================");
2867
2868
2869   set<int> faceNodes;  // ids of bottom face nodes, to be found
2870   set<int> checkedId1; // ids of tried 2-nd nodes
2871   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2872   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2873   int iMin, iLoop1 = 0;
2874
2875   // Loop to try the 2-nd nodes
2876
2877   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2878   {
2879     // Find not checked 2-nd node
2880     for ( i = 1; i < 8; i++ )
2881       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2882         int id1 = idNodes[i];
2883         swap ( 1, i, idNodes, P );
2884         checkedId1.insert ( id1 );
2885         break;
2886       }
2887
2888     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2889     // ie that all but meybe one (id3 which is on the same face) nodes
2890     // lay on the same side from the triangle plane.
2891
2892     bool manyInPlane = false; // more than 4 nodes lay in plane
2893     int iLoop2 = 0;
2894     while ( ++iLoop2 < 6 ) {
2895
2896       // get 1-2-3 plane coeffs
2897       Standard_Real A, B, C, D;
2898       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2899       if ( N.SquareMagnitude() > gp::Resolution() )
2900       {
2901         gp_Pln pln ( P[0], N );
2902         pln.Coefficients( A, B, C, D );
2903
2904         // find the node (iMin) closest to pln
2905         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2906         set<int> idInPln;
2907         for ( i = 3; i < 8; i++ ) {
2908           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2909           if ( fabs( dist[i] ) < minDist ) {
2910             minDist = fabs( dist[i] );
2911             iMin = i;
2912           }
2913           if ( fabs( dist[i] ) <= tol )
2914             idInPln.insert( idNodes[i] );
2915         }
2916
2917         // there should not be more than 4 nodes in bottom plane
2918         if ( idInPln.size() > 1 )
2919         {
2920           DUMPSO( "### idInPln.size() = " << idInPln.size());
2921           // idInPlane does not contain the first 3 nodes
2922           if ( manyInPlane || idInPln.size() == 5)
2923             return false; // all nodes in one plane
2924           manyInPlane = true;
2925
2926           // set the 1-st node to be not in plane
2927           for ( i = 3; i < 8; i++ ) {
2928             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2929               DUMPSO( "### Reset 0-th node");
2930               swap( 0, i, idNodes, P );
2931               break;
2932             }
2933           }
2934
2935           // reset to re-check second nodes
2936           leastDist = DBL_MAX;
2937           faceNodes.clear();
2938           checkedId1.clear();
2939           iLoop1 = 0;
2940           break; // from iLoop2;
2941         }
2942
2943         // check that the other 4 nodes are on the same side
2944         bool sameSide = true;
2945         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2946         for ( i = 3; sameSide && i < 8; i++ ) {
2947           if ( i != iMin )
2948             sameSide = ( isNeg == dist[i] <= 0.);
2949         }
2950
2951         // keep best solution
2952         if ( sameSide && minDist < leastDist ) {
2953           leastDist = minDist;
2954           faceNodes.clear();
2955           faceNodes.insert( idNodes[ 1 ] );
2956           faceNodes.insert( idNodes[ 2 ] );
2957           faceNodes.insert( idNodes[ iMin ] );
2958           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2959                   << " leastDist = " << leastDist);
2960           if ( leastDist <= DBL_MIN )
2961             break;
2962         }
2963       }
2964
2965       // set next 3-d node to check
2966       int iNext = 2 + iLoop2;
2967       if ( iNext < 8 ) {
2968         DUMPSO( "Try 2-nd");
2969         swap ( 2, iNext, idNodes, P );
2970       }
2971     } // while ( iLoop2 < 6 )
2972   } // iLoop1
2973
2974   if ( faceNodes.empty() ) return false;
2975
2976   // Put the faceNodes in proper places
2977   for ( i = 4; i < 8; i++ ) {
2978     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2979       // find a place to put
2980       int iTo = 1;
2981       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2982         iTo++;
2983       DUMPSO( "Set faceNodes");
2984       swap ( iTo, i, idNodes, P );
2985     }
2986   }
2987
2988
2989   // Set nodes of the found bottom face in good order
2990   DUMPSO( " Found bottom face: ");
2991   i = SortQuadNodes( theMesh, idNodes );
2992   if ( i ) {
2993     gp_Pnt Ptmp = P[ i ];
2994     P[ i ] = P[ i+1 ];
2995     P[ i+1 ] = Ptmp;
2996   }
2997   //   else
2998   //     for ( int ii = 0; ii < 4; ii++ ) {
2999   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
3000   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
3001   //    }
3002
3003   // Gravity center of the top and bottom faces
3004   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
3005   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
3006
3007   // Get direction from the bottom to the top face
3008   gp_Vec upDir ( aGCb, aGCt );
3009   Standard_Real upDirSize = upDir.Magnitude();
3010   if ( upDirSize <= gp::Resolution() ) return false;
3011   upDir / upDirSize;
3012
3013   // Assure that the bottom face normal points up
3014   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
3015   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
3016   if ( Nb.Dot( upDir ) < 0 ) {
3017     DUMPSO( "Reverse bottom face");
3018     swap( 1, 3, idNodes, P );
3019   }
3020
3021   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
3022   Standard_Real minDist = DBL_MAX;
3023   for ( i = 4; i < 8; i++ ) {
3024     // projection of P[i] to the plane defined by P[0] and upDir
3025     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
3026     Standard_Real sqDist = P[0].SquareDistance( Pp );
3027     if ( sqDist < minDist ) {
3028       minDist = sqDist;
3029       iMin = i;
3030     }
3031   }
3032   DUMPSO( "Set 4-th");
3033   swap ( 4, iMin, idNodes, P );
3034
3035   // Set nodes of the top face in good order
3036   DUMPSO( "Sort top face");
3037   i = SortQuadNodes( theMesh, &idNodes[4] );
3038   if ( i ) {
3039     i += 4;
3040     gp_Pnt Ptmp = P[ i ];
3041     P[ i ] = P[ i+1 ];
3042     P[ i+1 ] = Ptmp;
3043   }
3044
3045   // Assure that direction of the top face normal is from the bottom face
3046   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
3047   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
3048   if ( Nt.Dot( upDir ) < 0 ) {
3049     DUMPSO( "Reverse top face");
3050     swap( 5, 7, idNodes, P );
3051   }
3052
3053   //   DUMPSO( "OUTPUT: ========================================");
3054   //   for ( i = 0; i < 8; i++ ) {
3055   //     float *p = ugrid->GetPoint(idNodes[i]);
3056   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
3057   //   }
3058
3059   return true;
3060 }*/
3061
3062 //================================================================================
3063 /*!
3064  * \brief Return nodes linked to the given one
3065  * \param theNode - the node
3066  * \param linkedNodes - the found nodes
3067  * \param type - the type of elements to check
3068  *
3069  * Medium nodes are ignored
3070  */
3071 //================================================================================
3072
3073 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
3074                                        TIDSortedElemSet &   linkedNodes,
3075                                        SMDSAbs_ElementType  type )
3076 {
3077   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
3078   while ( elemIt->more() )
3079   {
3080     const SMDS_MeshElement* elem = elemIt->next();
3081     if(elem->GetType() == SMDSAbs_0DElement)
3082       continue;
3083
3084     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
3085     if ( elem->GetType() == SMDSAbs_Volume )
3086     {
3087       SMDS_VolumeTool vol( elem );
3088       while ( nodeIt->more() ) {
3089         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
3090         if ( theNode != n && vol.IsLinked( theNode, n ))
3091           linkedNodes.insert( n );
3092       }
3093     }
3094     else
3095     {
3096       for ( int i = 0; nodeIt->more(); ++i ) {
3097         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
3098         if ( n == theNode ) {
3099           int iBefore = i - 1;
3100           int iAfter  = i + 1;
3101           if ( elem->IsQuadratic() ) {
3102             int nb = elem->NbNodes() / 2;
3103             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
3104             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
3105           }
3106           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
3107           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
3108         }
3109       }
3110     }
3111   }
3112 }
3113
3114 //=======================================================================
3115 //function : laplacianSmooth
3116 //purpose  : pulls theNode toward the center of surrounding nodes directly
3117 //           connected to that node along an element edge
3118 //=======================================================================
3119
3120 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
3121                      const Handle(Geom_Surface)&          theSurface,
3122                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3123 {
3124   // find surrounding nodes
3125
3126   TIDSortedElemSet nodeSet;
3127   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
3128
3129   // compute new coodrs
3130
3131   double coord[] = { 0., 0., 0. };
3132   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
3133   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
3134     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
3135     if ( theSurface.IsNull() ) { // smooth in 3D
3136       coord[0] += node->X();
3137       coord[1] += node->Y();
3138       coord[2] += node->Z();
3139     }
3140     else { // smooth in 2D
3141       ASSERT( theUVMap.find( node ) != theUVMap.end() );
3142       gp_XY* uv = theUVMap[ node ];
3143       coord[0] += uv->X();
3144       coord[1] += uv->Y();
3145     }
3146   }
3147   int nbNodes = nodeSet.size();
3148   if ( !nbNodes )
3149     return;
3150   coord[0] /= nbNodes;
3151   coord[1] /= nbNodes;
3152
3153   if ( !theSurface.IsNull() ) {
3154     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
3155     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
3156     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
3157     coord[0] = p3d.X();
3158     coord[1] = p3d.Y();
3159     coord[2] = p3d.Z();
3160   }
3161   else
3162     coord[2] /= nbNodes;
3163
3164   // move node
3165
3166   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
3167 }
3168
3169 //=======================================================================
3170 //function : centroidalSmooth
3171 //purpose  : pulls theNode toward the element-area-weighted centroid of the
3172 //           surrounding elements
3173 //=======================================================================
3174
3175 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
3176                       const Handle(Geom_Surface)&          theSurface,
3177                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3178 {
3179   gp_XYZ aNewXYZ(0.,0.,0.);
3180   SMESH::Controls::Area anAreaFunc;
3181   double totalArea = 0.;
3182   int nbElems = 0;
3183
3184   // compute new XYZ
3185
3186   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
3187   while ( elemIt->more() )
3188   {
3189     const SMDS_MeshElement* elem = elemIt->next();
3190     nbElems++;
3191
3192     gp_XYZ elemCenter(0.,0.,0.);
3193     SMESH::Controls::TSequenceOfXYZ aNodePoints;
3194     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3195     int nn = elem->NbNodes();
3196     if(elem->IsQuadratic()) nn = nn/2;
3197     int i=0;
3198     //while ( itN->more() ) {
3199     while ( i<nn ) {
3200       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
3201       i++;
3202       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
3203       aNodePoints.push_back( aP );
3204       if ( !theSurface.IsNull() ) { // smooth in 2D
3205         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
3206         gp_XY* uv = theUVMap[ aNode ];
3207         aP.SetCoord( uv->X(), uv->Y(), 0. );
3208       }
3209       elemCenter += aP;
3210     }
3211     double elemArea = anAreaFunc.GetValue( aNodePoints );
3212     totalArea += elemArea;
3213     elemCenter /= nn;
3214     aNewXYZ += elemCenter * elemArea;
3215   }
3216   aNewXYZ /= totalArea;
3217   if ( !theSurface.IsNull() ) {
3218     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
3219     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
3220   }
3221
3222   // move node
3223
3224   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
3225 }
3226
3227 //=======================================================================
3228 //function : getClosestUV
3229 //purpose  : return UV of closest projection
3230 //=======================================================================
3231
3232 static bool getClosestUV (Extrema_GenExtPS& projector,
3233                           const gp_Pnt&     point,
3234                           gp_XY &           result)
3235 {
3236   projector.Perform( point );
3237   if ( projector.IsDone() ) {
3238     double u, v, minVal = DBL_MAX;
3239     for ( int i = projector.NbExt(); i > 0; i-- )
3240 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
3241       if ( projector.SquareDistance( i ) < minVal ) {
3242         minVal = projector.SquareDistance( i );
3243 #else
3244       if ( projector.Value( i ) < minVal ) {
3245         minVal = projector.Value( i );
3246 #endif
3247         projector.Point( i ).Parameter( u, v );
3248       }
3249     result.SetCoord( u, v );
3250     return true;
3251   }
3252   return false;
3253 }
3254
3255 //=======================================================================
3256 //function : Smooth
3257 //purpose  : Smooth theElements during theNbIterations or until a worst
3258 //           element has aspect ratio <= theTgtAspectRatio.
3259 //           Aspect Ratio varies in range [1.0, inf].
3260 //           If theElements is empty, the whole mesh is smoothed.
3261 //           theFixedNodes contains additionally fixed nodes. Nodes built
3262 //           on edges and boundary nodes are always fixed.
3263 //=======================================================================
3264
3265 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
3266                                set<const SMDS_MeshNode*> & theFixedNodes,
3267                                const SmoothMethod          theSmoothMethod,
3268                                const int                   theNbIterations,
3269                                double                      theTgtAspectRatio,
3270                                const bool                  the2D)
3271 {
3272   myLastCreatedElems.Clear();
3273   myLastCreatedNodes.Clear();
3274
3275   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
3276
3277   if ( theTgtAspectRatio < 1.0 )
3278     theTgtAspectRatio = 1.0;
3279
3280   const double disttol = 1.e-16;
3281
3282   SMESH::Controls::AspectRatio aQualityFunc;
3283
3284   SMESHDS_Mesh* aMesh = GetMeshDS();
3285
3286   if ( theElems.empty() ) {
3287     // add all faces to theElems
3288     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
3289     while ( fIt->more() ) {
3290       const SMDS_MeshElement* face = fIt->next();
3291       theElems.insert( theElems.end(), face );
3292     }
3293   }
3294   // get all face ids theElems are on
3295   set< int > faceIdSet;
3296   TIDSortedElemSet::iterator itElem;
3297   if ( the2D )
3298     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3299       int fId = FindShape( *itElem );
3300       // check that corresponding submesh exists and a shape is face
3301       if (fId &&
3302           faceIdSet.find( fId ) == faceIdSet.end() &&
3303           aMesh->MeshElements( fId )) {
3304         TopoDS_Shape F = aMesh->IndexToShape( fId );
3305         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
3306           faceIdSet.insert( fId );
3307       }
3308     }
3309   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
3310
3311   // ===============================================
3312   // smooth elements on each TopoDS_Face separately
3313   // ===============================================
3314
3315   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
3316   for ( ; fId != faceIdSet.rend(); ++fId ) {
3317     // get face surface and submesh
3318     Handle(Geom_Surface) surface;
3319     SMESHDS_SubMesh* faceSubMesh = 0;
3320     TopoDS_Face face;
3321     double fToler2 = 0, f,l;
3322     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
3323     bool isUPeriodic = false, isVPeriodic = false;
3324     if ( *fId ) {
3325       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
3326       surface = BRep_Tool::Surface( face );
3327       faceSubMesh = aMesh->MeshElements( *fId );
3328       fToler2 = BRep_Tool::Tolerance( face );
3329       fToler2 *= fToler2 * 10.;
3330       isUPeriodic = surface->IsUPeriodic();
3331       if ( isUPeriodic )
3332         surface->UPeriod();
3333       isVPeriodic = surface->IsVPeriodic();
3334       if ( isVPeriodic )
3335         surface->VPeriod();
3336       surface->Bounds( u1, u2, v1, v2 );
3337     }
3338     // ---------------------------------------------------------
3339     // for elements on a face, find movable and fixed nodes and
3340     // compute UV for them
3341     // ---------------------------------------------------------
3342     bool checkBoundaryNodes = false;
3343     bool isQuadratic = false;
3344     set<const SMDS_MeshNode*> setMovableNodes;
3345     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3346     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3347     list< const SMDS_MeshElement* > elemsOnFace;
3348
3349     Extrema_GenExtPS projector;
3350     GeomAdaptor_Surface surfAdaptor;
3351     if ( !surface.IsNull() ) {
3352       surfAdaptor.Load( surface );
3353       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3354     }
3355     int nbElemOnFace = 0;
3356     itElem = theElems.begin();
3357     // loop on not yet smoothed elements: look for elems on a face
3358     while ( itElem != theElems.end() ) {
3359       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3360         break; // all elements found
3361
3362       const SMDS_MeshElement* elem = *itElem;
3363       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3364            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3365         ++itElem;
3366         continue;
3367       }
3368       elemsOnFace.push_back( elem );
3369       theElems.erase( itElem++ );
3370       nbElemOnFace++;
3371
3372       if ( !isQuadratic )
3373         isQuadratic = elem->IsQuadratic();
3374
3375       // get movable nodes of elem
3376       const SMDS_MeshNode* node;
3377       SMDS_TypeOfPosition posType;
3378       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3379       int nn = 0, nbn =  elem->NbNodes();
3380       if(elem->IsQuadratic())
3381         nbn = nbn/2;
3382       while ( nn++ < nbn ) {
3383         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3384         const SMDS_PositionPtr& pos = node->GetPosition();
3385         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3386         if (posType != SMDS_TOP_EDGE &&
3387             posType != SMDS_TOP_VERTEX &&
3388             theFixedNodes.find( node ) == theFixedNodes.end())
3389         {
3390           // check if all faces around the node are on faceSubMesh
3391           // because a node on edge may be bound to face
3392           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3393           bool all = true;
3394           if ( faceSubMesh ) {
3395             while ( eIt->more() && all ) {
3396               const SMDS_MeshElement* e = eIt->next();
3397               all = faceSubMesh->Contains( e );
3398             }
3399           }
3400           if ( all )
3401             setMovableNodes.insert( node );
3402           else
3403             checkBoundaryNodes = true;
3404         }
3405         if ( posType == SMDS_TOP_3DSPACE )
3406           checkBoundaryNodes = true;
3407       }
3408
3409       if ( surface.IsNull() )
3410         continue;
3411
3412       // get nodes to check UV
3413       list< const SMDS_MeshNode* > uvCheckNodes;
3414       itN = elem->nodesIterator();
3415       nn = 0; nbn =  elem->NbNodes();
3416       if(elem->IsQuadratic())
3417         nbn = nbn/2;
3418       while ( nn++ < nbn ) {
3419         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3420         if ( uvMap.find( node ) == uvMap.end() )
3421           uvCheckNodes.push_back( node );
3422         // add nodes of elems sharing node
3423         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3424         //         while ( eIt->more() ) {
3425         //           const SMDS_MeshElement* e = eIt->next();
3426         //           if ( e != elem ) {
3427         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3428         //             while ( nIt->more() ) {
3429         //               const SMDS_MeshNode* n =
3430         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3431         //               if ( uvMap.find( n ) == uvMap.end() )
3432         //                 uvCheckNodes.push_back( n );
3433         //             }
3434         //           }
3435         //         }
3436       }
3437       // check UV on face
3438       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3439       for ( ; n != uvCheckNodes.end(); ++n ) {
3440         node = *n;
3441         gp_XY uv( 0, 0 );
3442         const SMDS_PositionPtr& pos = node->GetPosition();
3443         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3444         // get existing UV
3445         switch ( posType ) {
3446         case SMDS_TOP_FACE: {
3447           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3448           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3449           break;
3450         }
3451         case SMDS_TOP_EDGE: {
3452           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3453           Handle(Geom2d_Curve) pcurve;
3454           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3455             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3456           if ( !pcurve.IsNull() ) {
3457             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3458             uv = pcurve->Value( u ).XY();
3459           }
3460           break;
3461         }
3462         case SMDS_TOP_VERTEX: {
3463           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3464           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3465             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3466           break;
3467         }
3468         default:;
3469         }
3470         // check existing UV
3471         bool project = true;
3472         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3473         double dist1 = DBL_MAX, dist2 = 0;
3474         if ( posType != SMDS_TOP_3DSPACE ) {
3475           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3476           project = dist1 > fToler2;
3477         }
3478         if ( project ) { // compute new UV
3479           gp_XY newUV;
3480           if ( !getClosestUV( projector, pNode, newUV )) {
3481             MESSAGE("Node Projection Failed " << node);
3482           }
3483           else {
3484             if ( isUPeriodic )
3485               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3486             if ( isVPeriodic )
3487               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3488             // check new UV
3489             if ( posType != SMDS_TOP_3DSPACE )
3490               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3491             if ( dist2 < dist1 )
3492               uv = newUV;
3493           }
3494         }
3495         // store UV in the map
3496         listUV.push_back( uv );
3497         uvMap.insert( make_pair( node, &listUV.back() ));
3498       }
3499     } // loop on not yet smoothed elements
3500
3501     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3502       checkBoundaryNodes = true;
3503
3504     // fix nodes on mesh boundary
3505
3506     if ( checkBoundaryNodes ) {
3507       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3508       map< SMESH_TLink, int >::iterator link_nb;
3509       // put all elements links to linkNbMap
3510       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3511       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3512         const SMDS_MeshElement* elem = (*elemIt);
3513         int nbn =  elem->NbCornerNodes();
3514         // loop on elem links: insert them in linkNbMap
3515         for ( int iN = 0; iN < nbn; ++iN ) {
3516           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3517           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3518           SMESH_TLink link( n1, n2 );
3519           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3520           link_nb->second++;
3521         }
3522       }
3523       // remove nodes that are in links encountered only once from setMovableNodes
3524       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3525         if ( link_nb->second == 1 ) {
3526           setMovableNodes.erase( link_nb->first.node1() );
3527           setMovableNodes.erase( link_nb->first.node2() );
3528         }
3529       }
3530     }
3531
3532     // -----------------------------------------------------
3533     // for nodes on seam edge, compute one more UV ( uvMap2 );
3534     // find movable nodes linked to nodes on seam and which
3535     // are to be smoothed using the second UV ( uvMap2 )
3536     // -----------------------------------------------------
3537
3538     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3539     if ( !surface.IsNull() ) {
3540       TopExp_Explorer eExp( face, TopAbs_EDGE );
3541       for ( ; eExp.More(); eExp.Next() ) {
3542         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3543         if ( !BRep_Tool::IsClosed( edge, face ))
3544           continue;
3545         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3546         if ( !sm ) continue;
3547         // find out which parameter varies for a node on seam
3548         double f,l;
3549         gp_Pnt2d uv1, uv2;
3550         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3551         if ( pcurve.IsNull() ) continue;
3552         uv1 = pcurve->Value( f );
3553         edge.Reverse();
3554         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3555         if ( pcurve.IsNull() ) continue;
3556         uv2 = pcurve->Value( f );
3557         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3558         // assure uv1 < uv2
3559         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3560           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3561         }
3562         // get nodes on seam and its vertices
3563         list< const SMDS_MeshNode* > seamNodes;
3564         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3565         while ( nSeamIt->more() ) {
3566           const SMDS_MeshNode* node = nSeamIt->next();
3567           if ( !isQuadratic || !IsMedium( node ))
3568             seamNodes.push_back( node );
3569         }
3570         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3571         for ( ; vExp.More(); vExp.Next() ) {
3572           sm = aMesh->MeshElements( vExp.Current() );
3573           if ( sm ) {
3574             nSeamIt = sm->GetNodes();
3575             while ( nSeamIt->more() )
3576               seamNodes.push_back( nSeamIt->next() );
3577           }
3578         }
3579         // loop on nodes on seam
3580         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3581         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3582           const SMDS_MeshNode* nSeam = *noSeIt;
3583           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3584           if ( n_uv == uvMap.end() )
3585             continue;
3586           // set the first UV
3587           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3588           // set the second UV
3589           listUV.push_back( *n_uv->second );
3590           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3591           if ( uvMap2.empty() )
3592             uvMap2 = uvMap; // copy the uvMap contents
3593           uvMap2[ nSeam ] = &listUV.back();
3594
3595           // collect movable nodes linked to ones on seam in nodesNearSeam
3596           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3597           while ( eIt->more() ) {
3598             const SMDS_MeshElement* e = eIt->next();
3599             int nbUseMap1 = 0, nbUseMap2 = 0;
3600             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3601             int nn = 0, nbn =  e->NbNodes();
3602             if(e->IsQuadratic()) nbn = nbn/2;
3603             while ( nn++ < nbn )
3604             {
3605               const SMDS_MeshNode* n =
3606                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3607               if (n == nSeam ||
3608                   setMovableNodes.find( n ) == setMovableNodes.end() )
3609                 continue;
3610               // add only nodes being closer to uv2 than to uv1
3611               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3612                            0.5 * ( n->Y() + nSeam->Y() ),
3613                            0.5 * ( n->Z() + nSeam->Z() ));
3614               gp_XY uv;
3615               getClosestUV( projector, pMid, uv );
3616               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3617                 nodesNearSeam.insert( n );
3618                 nbUseMap2++;
3619               }
3620               else
3621                 nbUseMap1++;
3622             }
3623             // for centroidalSmooth all element nodes must
3624             // be on one side of a seam
3625             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3626               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3627               nn = 0;
3628               while ( nn++ < nbn ) {
3629                 const SMDS_MeshNode* n =
3630                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3631                 setMovableNodes.erase( n );
3632               }
3633             }
3634           }
3635         } // loop on nodes on seam
3636       } // loop on edge of a face
3637     } // if ( !face.IsNull() )
3638
3639     if ( setMovableNodes.empty() ) {
3640       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3641       continue; // goto next face
3642     }
3643
3644     // -------------
3645     // SMOOTHING //
3646     // -------------
3647
3648     int it = -1;
3649     double maxRatio = -1., maxDisplacement = -1.;
3650     set<const SMDS_MeshNode*>::iterator nodeToMove;
3651     for ( it = 0; it < theNbIterations; it++ ) {
3652       maxDisplacement = 0.;
3653       nodeToMove = setMovableNodes.begin();
3654       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3655         const SMDS_MeshNode* node = (*nodeToMove);
3656         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3657
3658         // smooth
3659         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3660         if ( theSmoothMethod == LAPLACIAN )
3661           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3662         else
3663           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3664
3665         // node displacement
3666         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3667         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3668         if ( aDispl > maxDisplacement )
3669           maxDisplacement = aDispl;
3670       }
3671       // no node movement => exit
3672       //if ( maxDisplacement < 1.e-16 ) {
3673       if ( maxDisplacement < disttol ) {
3674         MESSAGE("-- no node movement --");
3675         break;
3676       }
3677
3678       // check elements quality
3679       maxRatio  = 0;
3680       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3681       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3682         const SMDS_MeshElement* elem = (*elemIt);
3683         if ( !elem || elem->GetType() != SMDSAbs_Face )
3684           continue;
3685         SMESH::Controls::TSequenceOfXYZ aPoints;
3686         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3687           double aValue = aQualityFunc.GetValue( aPoints );
3688           if ( aValue > maxRatio )
3689             maxRatio = aValue;
3690         }
3691       }
3692       if ( maxRatio <= theTgtAspectRatio ) {
3693         MESSAGE("-- quality achived --");
3694         break;
3695       }
3696       if (it+1 == theNbIterations) {
3697         MESSAGE("-- Iteration limit exceeded --");
3698       }
3699     } // smoothing iterations
3700
3701     MESSAGE(" Face id: " << *fId <<
3702             " Nb iterstions: " << it <<
3703             " Displacement: " << maxDisplacement <<
3704             " Aspect Ratio " << maxRatio);
3705
3706     // ---------------------------------------
3707     // new nodes positions are computed,
3708     // record movement in DS and set new UV
3709     // ---------------------------------------
3710     nodeToMove = setMovableNodes.begin();
3711     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3712       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3713       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3714       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3715       if ( node_uv != uvMap.end() ) {
3716         gp_XY* uv = node_uv->second;
3717         node->SetPosition
3718           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3719       }
3720     }
3721
3722     // move medium nodes of quadratic elements
3723     if ( isQuadratic )
3724     {
3725       SMESH_MesherHelper helper( *GetMesh() );
3726       helper.SetSubShape( face );
3727       vector<const SMDS_MeshNode*> nodes;
3728       bool checkUV;
3729       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3730       for ( ; elemIt != elemsOnFace.end(); ++elemIt )
3731       {
3732         const SMDS_MeshElement* QF = *elemIt;
3733         if ( QF->IsQuadratic() )
3734         {
3735           nodes.assign( SMDS_MeshElement::iterator( QF->interlacedNodesElemIterator() ),
3736                         SMDS_MeshElement::iterator() );
3737           nodes.push_back( nodes[0] );
3738           gp_Pnt xyz;
3739           for (size_t i = 1; i < nodes.size(); i += 2 ) // i points to a medium node
3740           {
3741             if ( !surface.IsNull() )
3742             {
3743               gp_XY uv1 = helper.GetNodeUV( face, nodes[i-1], nodes[i+1], &checkUV );
3744               gp_XY uv2 = helper.GetNodeUV( face, nodes[i+1], nodes[i-1], &checkUV );
3745               gp_XY uv  = helper.GetMiddleUV( surface, uv1, uv2 );
3746               xyz = surface->Value( uv.X(), uv.Y() );
3747             }
3748             else {
3749               xyz = 0.5 * ( SMESH_TNodeXYZ( nodes[i-1] ) + SMESH_TNodeXYZ( nodes[i+1] ));
3750             }
3751             if (( SMESH_TNodeXYZ( nodes[i] ) - xyz.XYZ() ).Modulus() > disttol )
3752               // we have to move a medium node
3753               aMesh->MoveNode( nodes[i], xyz.X(), xyz.Y(), xyz.Z() );
3754           }
3755         }
3756       }
3757     }
3758
3759   } // loop on face ids
3760
3761 }
3762
3763 //=======================================================================
3764 //function : isReverse
3765 //purpose  : Return true if normal of prevNodes is not co-directied with
3766 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3767 //           iNotSame is where prevNodes and nextNodes are different.
3768 //           If result is true then future volume orientation is OK
3769 //=======================================================================
3770
3771 static bool isReverse(const SMDS_MeshElement*             face,
3772                       const vector<const SMDS_MeshNode*>& prevNodes,
3773                       const vector<const SMDS_MeshNode*>& nextNodes,
3774                       const int                           iNotSame)
3775 {
3776
3777   SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
3778   SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
3779   gp_XYZ extrDir( pN - pP ), faceNorm;
3780   SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false );
3781
3782   return faceNorm * extrDir < 0.0;
3783 }
3784
3785 //=======================================================================
3786 /*!
3787  * \brief Create elements by sweeping an element
3788  * \param elem - element to sweep
3789  * \param newNodesItVec - nodes generated from each node of the element
3790  * \param newElems - generated elements
3791  * \param nbSteps - number of sweeping steps
3792  * \param srcElements - to append elem for each generated element
3793  */
3794 //=======================================================================
3795
3796 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3797                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3798                                     list<const SMDS_MeshElement*>&        newElems,
3799                                     const int                             nbSteps,
3800                                     SMESH_SequenceOfElemPtr&              srcElements)
3801 {
3802   //MESSAGE("sweepElement " << nbSteps);
3803   SMESHDS_Mesh* aMesh = GetMeshDS();
3804
3805   const int           nbNodes = elem->NbNodes();
3806   const int         nbCorners = elem->NbCornerNodes();
3807   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of
3808                                                           polyhedron creation !!! */
3809   // Loop on elem nodes:
3810   // find new nodes and detect same nodes indices
3811   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3812   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3813   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3814   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3815
3816   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
3817   vector<int> sames(nbNodes);
3818   vector<bool> isSingleNode(nbNodes);
3819
3820   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3821     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
3822     const SMDS_MeshNode*                         node = nnIt->first;
3823     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3824     if ( listNewNodes.empty() )
3825       return;
3826
3827     itNN   [ iNode ] = listNewNodes.begin();
3828     prevNod[ iNode ] = node;
3829     nextNod[ iNode ] = listNewNodes.front();
3830
3831     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
3832                                                              corner node of linear */
3833     if ( prevNod[ iNode ] != nextNod [ iNode ])
3834       nbDouble += !isSingleNode[iNode];
3835
3836     if( iNode < nbCorners ) { // check corners only
3837       if ( prevNod[ iNode ] == nextNod [ iNode ])
3838         sames[nbSame++] = iNode;
3839       else
3840         iNotSameNode = iNode;
3841     }
3842   }
3843
3844   if ( nbSame == nbNodes || nbSame > 2) {
3845     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3846     return;
3847   }
3848
3849   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
3850   {
3851     // fix nodes order to have bottom normal external
3852     if ( baseType == SMDSEntity_Polygon )
3853     {
3854       std::reverse( itNN.begin(), itNN.end() );
3855       std::reverse( prevNod.begin(), prevNod.end() );
3856       std::reverse( midlNod.begin(), midlNod.end() );
3857       std::reverse( nextNod.begin(), nextNod.end() );
3858       std::reverse( isSingleNode.begin(), isSingleNode.end() );
3859     }
3860     else
3861     {
3862       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
3863       SMDS_MeshCell::applyInterlace( ind, itNN );
3864       SMDS_MeshCell::applyInterlace( ind, prevNod );
3865       SMDS_MeshCell::applyInterlace( ind, nextNod );
3866       SMDS_MeshCell::applyInterlace( ind, midlNod );
3867       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3868       if ( nbSame > 0 )
3869       {
3870         sames[nbSame] = iNotSameNode;
3871         for ( int j = 0; j <= nbSame; ++j )
3872           for ( size_t i = 0; i < ind.size(); ++i )
3873             if ( ind[i] == sames[j] )
3874             {
3875               sames[j] = i;
3876               break;
3877             }
3878         iNotSameNode = sames[nbSame];
3879       }
3880     }
3881   }
3882
3883   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3884   if ( nbSame > 0 ) {
3885     iSameNode    = sames[ nbSame-1 ];
3886     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
3887     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
3888     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3889   }
3890
3891   // make new elements
3892   for (int iStep = 0; iStep < nbSteps; iStep++ )
3893   {
3894     // get next nodes
3895     for ( iNode = 0; iNode < nbNodes; iNode++ )
3896     {
3897       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
3898       nextNod[ iNode ] = *itNN[ iNode ]++;
3899     }
3900
3901     SMDS_MeshElement* aNewElem = 0;
3902     /*if(!elem->IsPoly())*/ {
3903       switch ( baseType ) {
3904       case SMDSEntity_0D:
3905       case SMDSEntity_Node: { // sweep NODE
3906         if ( nbSame == 0 ) {
3907           if ( isSingleNode[0] )
3908             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3909           else
3910             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3911         }
3912         else
3913           return;
3914         break;
3915       }
3916       case SMDSEntity_Edge: { // sweep EDGE
3917         if ( nbDouble == 0 )
3918         {
3919           if ( nbSame == 0 ) // ---> quadrangle
3920             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3921                                       nextNod[ 1 ], nextNod[ 0 ] );
3922           else               // ---> triangle
3923             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3924                                       nextNod[ iNotSameNode ] );
3925         }
3926         else                 // ---> polygon
3927         {
3928           vector<const SMDS_MeshNode*> poly_nodes;
3929           poly_nodes.push_back( prevNod[0] );
3930           poly_nodes.push_back( prevNod[1] );
3931           if ( prevNod[1] != nextNod[1] )
3932           {
3933             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
3934             poly_nodes.push_back( nextNod[1] );
3935           }
3936           if ( prevNod[0] != nextNod[0] )
3937           {
3938             poly_nodes.push_back( nextNod[0] );
3939             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
3940           }
3941           switch ( poly_nodes.size() ) {
3942           case 3:
3943             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
3944             break;
3945           case 4:
3946             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
3947                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
3948             break;
3949           default:
3950             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
3951           }
3952         }
3953         break;
3954       }
3955       case SMDSEntity_Triangle: // TRIANGLE --->
3956         {
3957           if ( nbDouble > 0 ) break;
3958           if ( nbSame == 0 )       // ---> pentahedron
3959             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3960                                          nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
3961
3962           else if ( nbSame == 1 )  // ---> pyramid
3963             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3964                                          nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3965                                          nextNod[ iSameNode ]);
3966
3967           else // 2 same nodes:       ---> tetrahedron
3968             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3969                                          nextNod[ iNotSameNode ]);
3970           break;
3971         }
3972       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
3973         {
3974           if ( nbSame == 2 )
3975             return;
3976           if ( nbDouble+nbSame == 2 )
3977           {
3978             if(nbSame==0) {      // ---> quadratic quadrangle
3979               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3980                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
3981             }
3982             else { //(nbSame==1) // ---> quadratic triangle
3983               if(sames[0]==2) {
3984                 return; // medium node on axis
3985               }
3986               else if(sames[0]==0)
3987                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3988                                           nextNod[2], midlNod[1], prevNod[2]);
3989               else // sames[0]==1
3990                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3991                                           midlNod[0], nextNod[2], prevNod[2]);
3992             }
3993           }
3994           else if ( nbDouble == 3 )
3995           {
3996             if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
3997               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3998                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
3999             }
4000           }
4001           else
4002             return;
4003           break;
4004         }
4005       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
4006         if ( nbDouble > 0 ) break;
4007
4008         if ( nbSame == 0 )       // ---> hexahedron
4009           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
4010                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
4011
4012         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
4013           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
4014                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
4015                                        nextNod[ iSameNode ]);
4016           newElems.push_back( aNewElem );
4017           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
4018                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
4019                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
4020         }
4021         else if ( nbSame == 2 ) { // ---> pentahedron
4022           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
4023             // iBeforeSame is same too
4024             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
4025                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
4026                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
4027           else
4028             // iAfterSame is same too
4029             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
4030                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
4031                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
4032         }
4033         break;
4034       }
4035       case SMDSEntity_Quad_Triangle:  // sweep (Bi)Quadratic TRIANGLE --->
4036       case SMDSEntity_BiQuad_Triangle: /* ??? */ { 
4037         if ( nbDouble+nbSame != 3 ) break;
4038         if(nbSame==0) {
4039           // --->  pentahedron with 15 nodes
4040           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
4041                                        nextNod[0], nextNod[1], nextNod[2],
4042                                        prevNod[3], prevNod[4], prevNod[5],
4043                                        nextNod[3], nextNod[4], nextNod[5],
4044                                        midlNod[0], midlNod[1], midlNod[2]);
4045         }
4046         else if(nbSame==1) {
4047           // --->  2d order pyramid of 13 nodes
4048           int apex = iSameNode;
4049           int i0 = ( apex + 1 ) % nbCorners;
4050           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
4051           int i0a = apex + 3;
4052           int i1a = i1 + 3;
4053           int i01 = i0 + 3;
4054           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
4055                                       nextNod[i0], nextNod[i1], prevNod[apex],
4056                                       prevNod[i01], midlNod[i0],
4057                                       nextNod[i01], midlNod[i1],
4058                                       prevNod[i1a], prevNod[i0a],
4059                                       nextNod[i0a], nextNod[i1a]);
4060         }
4061         else if(nbSame==2) {
4062           // --->  2d order tetrahedron of 10 nodes
4063           int n1 = iNotSameNode;
4064           int n2 = ( n1 + 1             ) % nbCorners;
4065           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
4066           int n12 = n1 + 3;
4067           int n23 = n2 + 3;
4068           int n31 = n3 + 3;
4069           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
4070                                        prevNod[n12], prevNod[n23], prevNod[n31],
4071                                        midlNod[n1], nextNod[n12], nextNod[n31]);
4072         }
4073         break;
4074       }
4075       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
4076         if( nbSame == 0 ) {
4077           if ( nbDouble != 4 ) break;
4078           // --->  hexahedron with 20 nodes
4079           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
4080                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
4081                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
4082                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
4083                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
4084         }
4085         else if(nbSame==1) {
4086           // ---> pyramid + pentahedron - can not be created since it is needed
4087           // additional middle node at the center of face
4088           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
4089           return;
4090         }
4091         else if( nbSame == 2 ) {
4092           if ( nbDouble != 2 ) break;
4093           // --->  2d order Pentahedron with 15 nodes
4094           int n1,n2,n4,n5;
4095           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
4096             // iBeforeSame is same too
4097             n1 = iBeforeSame;
4098             n2 = iOpposSame;
4099             n4 = iSameNode;
4100             n5 = iAfterSame;
4101           }
4102           else {
4103             // iAfterSame is same too
4104             n1 = iSameNode;
4105             n2 = iBeforeSame;
4106             n4 = iAfterSame;
4107             n5 = iOpposSame;
4108           }
4109           int n12 = n2 + 4;
4110           int n45 = n4 + 4;
4111           int n14 = n1 + 4;
4112           int n25 = n5 + 4;
4113           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
4114                                        prevNod[n4], prevNod[n5], nextNod[n5],
4115                                        prevNod[n12], midlNod[n2], nextNod[n12],
4116                                        prevNod[n45], midlNod[n5], nextNod[n45],
4117                                        prevNod[n14], prevNod[n25], nextNod[n25]);
4118         }
4119         break;
4120       }
4121       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
4122
4123         if( nbSame == 0 && nbDouble == 9 ) {
4124           // --->  tri-quadratic hexahedron with 27 nodes
4125           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
4126                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
4127                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
4128                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
4129                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
4130                                        prevNod[8], // bottom center
4131                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
4132                                        nextNod[8], // top center
4133                                        midlNod[8]);// elem center
4134         }
4135         else
4136         {
4137           return;
4138         }
4139         break;
4140       }
4141       case SMDSEntity_Polygon: { // sweep POLYGON
4142
4143         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
4144           // --->  hexagonal prism
4145           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
4146                                        prevNod[3], prevNod[4], prevNod[5],
4147                                        nextNod[0], nextNod[1], nextNod[2],
4148                                        nextNod[3], nextNod[4], nextNod[5]);
4149         }
4150         break;
4151       }
4152       case SMDSEntity_Ball:
4153         return;
4154
4155       default:
4156         break;
4157       }
4158     }
4159
4160     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
4161     {
4162       if ( baseType != SMDSEntity_Polygon )
4163       {
4164         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
4165         SMDS_MeshCell::applyInterlace( ind, prevNod );
4166         SMDS_MeshCell::applyInterlace( ind, nextNod );
4167         SMDS_MeshCell::applyInterlace( ind, midlNod );
4168         SMDS_MeshCell::applyInterlace( ind, itNN );
4169         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
4170         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
4171       }
4172       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
4173       vector<int> quantities (nbNodes + 2);
4174       polyedre_nodes.clear();
4175       quantities.clear();
4176
4177       // bottom of prism
4178       for (int inode = 0; inode < nbNodes; inode++)
4179         polyedre_nodes.push_back( prevNod[inode] );
4180       quantities.push_back( nbNodes );
4181
4182       // top of prism
4183       polyedre_nodes.push_back( nextNod[0] );
4184       for (int inode = nbNodes; inode-1; --inode )
4185         polyedre_nodes.push_back( nextNod[inode-1] );
4186       quantities.push_back( nbNodes );
4187
4188       // side faces
4189       for (int iface = 0; iface < nbNodes; iface++)
4190       {
4191         const int prevNbNodes = polyedre_nodes.size();
4192         int inextface = (iface+1) % nbNodes;
4193         polyedre_nodes.push_back( prevNod[inextface] );
4194         polyedre_nodes.push_back( prevNod[iface] );
4195         if ( prevNod[iface] != nextNod[iface] )
4196         {
4197           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
4198           polyedre_nodes.push_back( nextNod[iface] );
4199         }
4200         if ( prevNod[inextface] != nextNod[inextface] )
4201         {
4202           polyedre_nodes.push_back( nextNod[inextface] );
4203           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
4204         }
4205         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
4206         if ( nbFaceNodes > 2 )
4207           quantities.push_back( nbFaceNodes );
4208         else // degenerated face
4209           polyedre_nodes.resize( prevNbNodes );
4210       }
4211       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
4212     }
4213
4214     if ( aNewElem ) {
4215       newElems.push_back( aNewElem );
4216       myLastCreatedElems.Append(aNewElem);
4217       srcElements.Append( elem );
4218     }
4219
4220     // set new prev nodes
4221     for ( iNode = 0; iNode < nbNodes; iNode++ )
4222       prevNod[ iNode ] = nextNod[ iNode ];
4223
4224   } // for steps
4225 }
4226
4227 //=======================================================================
4228 /*!
4229  * \brief Create 1D and 2D elements around swept elements
4230  * \param mapNewNodes - source nodes and ones generated from them
4231  * \param newElemsMap - source elements and ones generated from them
4232  * \param elemNewNodesMap - nodes generated from each node of each element
4233  * \param elemSet - all swept elements
4234  * \param nbSteps - number of sweeping steps
4235  * \param srcElements - to append elem for each generated element
4236  */
4237 //=======================================================================
4238
4239 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
4240                                   TElemOfElemListMap &     newElemsMap,
4241                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
4242                                   TIDSortedElemSet&        elemSet,
4243                                   const int                nbSteps,
4244                                   SMESH_SequenceOfElemPtr& srcElements)
4245 {
4246   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
4247   SMESHDS_Mesh* aMesh = GetMeshDS();
4248
4249   // Find nodes belonging to only one initial element - sweep them into edges.
4250
4251   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
4252   for ( ; nList != mapNewNodes.end(); nList++ )
4253   {
4254     const SMDS_MeshNode* node =
4255       static_cast<const SMDS_MeshNode*>( nList->first );
4256     if ( newElemsMap.count( node ))
4257       continue; // node was extruded into edge
4258     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
4259     int nbInitElems = 0;
4260     const SMDS_MeshElement* el = 0;
4261     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
4262     while ( eIt->more() && nbInitElems < 2 ) {
4263       el = eIt->next();
4264       SMDSAbs_ElementType type = el->GetType();
4265       if ( type == SMDSAbs_Volume || type < highType ) continue;
4266       if ( type > highType ) {
4267         nbInitElems = 0;
4268         highType = type;
4269       }
4270       nbInitElems += elemSet.count(el);
4271     }
4272     if ( nbInitElems < 2 ) {
4273       bool NotCreateEdge = el && el->IsMediumNode(node);
4274       if(!NotCreateEdge) {
4275         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
4276         list<const SMDS_MeshElement*> newEdges;
4277         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
4278       }
4279     }
4280   }
4281
4282   // Make a ceiling for each element ie an equal element of last new nodes.
4283   // Find free links of faces - make edges and sweep them into faces.
4284
4285   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
4286   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
4287   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
4288   {
4289     const SMDS_MeshElement* elem = itElem->first;
4290     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
4291
4292     if(itElem->second.size()==0) continue;
4293
4294     const bool isQuadratic = elem->IsQuadratic();
4295
4296     if ( elem->GetType() == SMDSAbs_Edge ) {
4297       // create a ceiling edge
4298       if ( !isQuadratic ) {
4299         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4300                                vecNewNodes[ 1 ]->second.back())) {
4301           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4302                                                    vecNewNodes[ 1 ]->second.back()));
4303           srcElements.Append( elem );
4304         }
4305       }
4306       else {
4307         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4308                                vecNewNodes[ 1 ]->second.back(),
4309                                vecNewNodes[ 2 ]->second.back())) {
4310           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4311                                                    vecNewNodes[ 1 ]->second.back(),
4312                                                    vecNewNodes[ 2 ]->second.back()));
4313           srcElements.Append( elem );
4314         }
4315       }
4316     }
4317     if ( elem->GetType() != SMDSAbs_Face )
4318       continue;
4319
4320     bool hasFreeLinks = false;
4321
4322     TIDSortedElemSet avoidSet;
4323     avoidSet.insert( elem );
4324
4325     set<const SMDS_MeshNode*> aFaceLastNodes;
4326     int iNode, nbNodes = vecNewNodes.size();
4327     if ( !isQuadratic ) {
4328       // loop on the face nodes
4329       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4330         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4331         // look for free links of the face
4332         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4333         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4334         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4335         // check if a link n1-n2 is free
4336         if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4337           hasFreeLinks = true;
4338           // make a new edge and a ceiling for a new edge
4339           const SMDS_MeshElement* edge;
4340           if ( ! ( edge = aMesh->FindEdge( n1, n2 ))) {
4341             myLastCreatedElems.Append( edge = aMesh->AddEdge( n1, n2 )); // free link edge
4342             srcElements.Append( myLastCreatedElems.Last() );
4343           }
4344           n1 = vecNewNodes[ iNode ]->second.back();
4345           n2 = vecNewNodes[ iNext ]->second.back();
4346           if ( !aMesh->FindEdge( n1, n2 )) {
4347             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling
4348             srcElements.Append( edge );
4349           }
4350         }
4351       }
4352     }
4353     else { // elem is quadratic face
4354       int nbn = nbNodes/2;
4355       for ( iNode = 0; iNode < nbn; iNode++ ) {
4356         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4357         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4358         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4359         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4360         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4361         // check if a link is free
4362         if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4363              ! SMESH_MeshAlgos::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4364              ! SMESH_MeshAlgos::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4365           hasFreeLinks = true;
4366           // make an edge and a ceiling for a new edge
4367           // find medium node
4368           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4369             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4370             srcElements.Append( elem );
4371           }
4372           n1 = vecNewNodes[ iNode ]->second.back();
4373           n2 = vecNewNodes[ iNext ]->second.back();
4374           n3 = vecNewNodes[ iNode+nbn ]->second.back();
4375           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4376             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4377             srcElements.Append( elem );
4378           }
4379         }
4380       }
4381       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4382         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4383       }
4384     }
4385
4386     // sweep free links into faces
4387
4388     if ( hasFreeLinks )  {
4389       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4390       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4391
4392       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4393       set<const SMDS_MeshNode*> initNodeSetNoCenter/*, topNodeSetNoCenter*/;
4394       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4395         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4396         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4397       }
4398       if ( isQuadratic && nbNodes % 2 ) {  // node set for the case of a biquadratic
4399         initNodeSetNoCenter = initNodeSet; // swept face and a not biquadratic volume
4400         initNodeSetNoCenter.erase( vecNewNodes.back()->first );
4401       }
4402       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4403         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4404         std::advance( v, volNb );
4405         // find indices of free faces of a volume and their source edges
4406         list< int > freeInd;
4407         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4408         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4409         int iF, nbF = vTool.NbFaces();
4410         for ( iF = 0; iF < nbF; iF ++ ) {
4411           if (vTool.IsFreeFace( iF ) &&
4412               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4413               initNodeSet != faceNodeSet) // except an initial face
4414           {
4415             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4416               continue;
4417             if ( faceNodeSet == initNodeSetNoCenter )
4418               continue;
4419             freeInd.push_back( iF );
4420             // find source edge of a free face iF
4421             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4422             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4423             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4424                                    initNodeSet.begin(), initNodeSet.end(),
4425                                    commonNodes.begin());
4426             if ( (*v)->IsQuadratic() )
4427               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4428             else
4429               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4430 #ifdef _DEBUG_
4431             if ( !srcEdges.back() )
4432             {
4433               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4434                    << iF << " of volume #" << vTool.ID() << endl;
4435             }
4436 #endif
4437           }
4438         }
4439         if ( freeInd.empty() )
4440           continue;
4441
4442         // create faces for all steps;
4443         // if such a face has been already created by sweep of edge,
4444         // assure that its orientation is OK
4445         for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4446           vTool.Set( *v, /*ignoreCentralNodes=*/false );
4447           vTool.SetExternalNormal();
4448           const int nextShift = vTool.IsForward() ? +1 : -1;
4449           list< int >::iterator ind = freeInd.begin();
4450           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4451           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4452           {
4453             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4454             int nbn = vTool.NbFaceNodes( *ind );
4455             const SMDS_MeshElement * f = 0;
4456             if ( nbn == 3 )              ///// triangle
4457             {
4458               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4459               if ( !f ||
4460                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4461               {
4462                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4463                                                      nodes[ 1 ],
4464                                                      nodes[ 1 + nextShift ] };
4465                 if ( f )
4466                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4467                 else
4468                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4469                                                             newOrder[ 2 ] ));
4470               }
4471             }
4472             else if ( nbn == 4 )       ///// quadrangle
4473             {
4474               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4475               if ( !f ||
4476                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4477               {
4478                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4479                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
4480                 if ( f )
4481                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4482                 else
4483                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4484                                                             newOrder[ 2 ], newOrder[ 3 ]));
4485               }
4486             }
4487             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4488             {
4489               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4490               if ( !f ||
4491                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4492               {
4493                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4494                                                      nodes[2],
4495                                                      nodes[2 + 2*nextShift],
4496                                                      nodes[3 - 2*nextShift],
4497                                                      nodes[3],
4498                                                      nodes[3 + 2*nextShift]};
4499                 if ( f )
4500                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4501                 else
4502                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4503                                                             newOrder[ 1 ],
4504                                                             newOrder[ 2 ],
4505                                                             newOrder[ 3 ],
4506                                                             newOrder[ 4 ],
4507                                                             newOrder[ 5 ] ));
4508               }
4509             }
4510             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4511             {
4512               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4513                                    nodes[1], nodes[3], nodes[5], nodes[7] );
4514               if ( !f ||
4515                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4516               {
4517                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4518                                                      nodes[4 - 2*nextShift],
4519                                                      nodes[4],
4520                                                      nodes[4 + 2*nextShift],
4521                                                      nodes[1],
4522                                                      nodes[5 - 2*nextShift],
4523                                                      nodes[5],
4524                                                      nodes[5 + 2*nextShift] };
4525                 if ( f )
4526                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4527                 else
4528                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4529                                                            newOrder[ 2 ], newOrder[ 3 ],
4530                                                            newOrder[ 4 ], newOrder[ 5 ],
4531                                                            newOrder[ 6 ], newOrder[ 7 ]));
4532               }
4533             }
4534             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4535             {
4536               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4537                                       SMDSAbs_Face, /*noMedium=*/false);
4538               if ( !f ||
4539                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4540               {
4541                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
4542                                                      nodes[4 - 2*nextShift],
4543                                                      nodes[4],
4544                                                      nodes[4 + 2*nextShift],
4545                                                      nodes[1],
4546                                                      nodes[5 - 2*nextShift],
4547                                                      nodes[5],
4548                                                      nodes[5 + 2*nextShift],
4549                                                      nodes[8] };
4550                 if ( f )
4551                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4552                 else
4553                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4554                                                            newOrder[ 2 ], newOrder[ 3 ],
4555                                                            newOrder[ 4 ], newOrder[ 5 ],
4556                                                            newOrder[ 6 ], newOrder[ 7 ],
4557                                                            newOrder[ 8 ]));
4558               }
4559             }
4560             else  //////// polygon
4561             {
4562               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
4563               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4564               if ( !f ||
4565                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4566               {
4567                 if ( !vTool.IsForward() )
4568                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4569                 if ( f )
4570                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4571                 else
4572                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4573               }
4574             }
4575
4576             while ( srcElements.Length() < myLastCreatedElems.Length() )
4577               srcElements.Append( *srcEdge );
4578
4579           }  // loop on free faces
4580
4581           // go to the next volume
4582           iVol = 0;
4583           while ( iVol++ < nbVolumesByStep ) v++;
4584
4585         } // loop on steps
4586       } // loop on volumes of one step
4587     } // sweep free links into faces
4588
4589     // Make a ceiling face with a normal external to a volume
4590
4591     // use SMDS_VolumeTool to get a correctly ordered nodes of a ceiling face
4592     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
4593     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4594
4595     if ( iF < 0 && isQuadratic && nbNodes % 2 ) { // remove a central node of biquadratic
4596       aFaceLastNodes.erase( vecNewNodes.back()->second.back() );
4597       iF = lastVol.GetFaceIndex( aFaceLastNodes );
4598     }
4599     if ( iF >= 0 ) {
4600       lastVol.SetExternalNormal();
4601       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4602       int nbn = lastVol.NbFaceNodes( iF );
4603       // we do not use this->AddElement() because nodes are interlaced
4604       vector<const SMDS_MeshNode*> nodeVec( nodes, nodes+nbn );
4605       if ( !hasFreeLinks ||
4606            !aMesh->FindElement( nodeVec, SMDSAbs_Face, /*noMedium=*/false) )
4607       {
4608         if ( nbn == 3 )
4609           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2] ));
4610
4611         else if ( nbn == 4 )
4612           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2], nodes[3]));
4613
4614         else if ( nbn == 6 && isQuadratic )
4615           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4],
4616                                                     nodes[1], nodes[3], nodes[5]));
4617         else if ( nbn == 7 && isQuadratic )
4618           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4],
4619                                                     nodes[1], nodes[3], nodes[5], nodes[6]));
4620         else if ( nbn == 8 && isQuadratic )
4621           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], nodes[6],
4622                                                     nodes[1], nodes[3], nodes[5], nodes[7]));
4623         else if ( nbn == 9 && isQuadratic )
4624           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], nodes[6],
4625                                                     nodes[1], nodes[3], nodes[5], nodes[7],
4626                                                     nodes[8]));
4627         else
4628           myLastCreatedElems.Append(aMesh->AddPolygonalFace( nodeVec ));
4629
4630         while ( srcElements.Length() < myLastCreatedElems.Length() )
4631           srcElements.Append( elem );
4632       }
4633     }
4634   } // loop on swept elements
4635 }
4636
4637 //=======================================================================
4638 //function : RotationSweep
4639 //purpose  :
4640 //=======================================================================
4641
4642 SMESH_MeshEditor::PGroupIDs
4643 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4644                                 const gp_Ax1&      theAxis,
4645                                 const double       theAngle,
4646                                 const int          theNbSteps,
4647                                 const double       theTol,
4648                                 const bool         theMakeGroups,
4649                                 const bool         theMakeWalls)
4650 {
4651   myLastCreatedElems.Clear();
4652   myLastCreatedNodes.Clear();
4653
4654   // source elements for each generated one
4655   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4656
4657   MESSAGE( "RotationSweep()");
4658   gp_Trsf aTrsf;
4659   aTrsf.SetRotation( theAxis, theAngle );
4660   gp_Trsf aTrsf2;
4661   aTrsf2.SetRotation( theAxis, theAngle/2. );
4662
4663   gp_Lin aLine( theAxis );
4664   double aSqTol = theTol * theTol;
4665
4666   SMESHDS_Mesh* aMesh = GetMeshDS();
4667
4668   TNodeOfNodeListMap mapNewNodes;
4669   TElemOfVecOfNnlmiMap mapElemNewNodes;
4670   TElemOfElemListMap newElemsMap;
4671
4672   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4673                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4674                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4675   // loop on theElems
4676   TIDSortedElemSet::iterator itElem;
4677   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4678     const SMDS_MeshElement* elem = *itElem;
4679     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4680       continue;
4681     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4682     newNodesItVec.reserve( elem->NbNodes() );
4683
4684     // loop on elem nodes
4685     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4686     while ( itN->more() )
4687     {
4688       // check if a node has been already sweeped
4689       const SMDS_MeshNode* node = cast2Node( itN->next() );
4690
4691       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4692       double coord[3];
4693       aXYZ.Coord( coord[0], coord[1], coord[2] );
4694       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4695
4696       TNodeOfNodeListMapItr nIt =
4697         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4698       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4699       if ( listNewNodes.empty() )
4700       {
4701         // check if we are to create medium nodes between corner ones
4702         bool needMediumNodes = false;
4703         if ( isQuadraticMesh )
4704         {
4705           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4706           while (it->more() && !needMediumNodes )
4707           {
4708             const SMDS_MeshElement* invElem = it->next();
4709             if ( invElem != elem && !theElems.count( invElem )) continue;
4710             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4711             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4712               needMediumNodes = true;
4713           }
4714         }
4715
4716         // make new nodes
4717         const SMDS_MeshNode * newNode = node;
4718         for ( int i = 0; i < theNbSteps; i++ ) {
4719           if ( !isOnAxis ) {
4720             if ( needMediumNodes )  // create a medium node
4721             {
4722               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4723               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4724               myLastCreatedNodes.Append(newNode);
4725               srcNodes.Append( node );
4726               listNewNodes.push_back( newNode );
4727               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4728             }
4729             else {
4730               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4731             }
4732             // create a corner node
4733             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4734             myLastCreatedNodes.Append(newNode);
4735             srcNodes.Append( node );
4736             listNewNodes.push_back( newNode );
4737           }
4738           else {
4739             listNewNodes.push_back( newNode );
4740             // if ( needMediumNodes )
4741             //   listNewNodes.push_back( newNode );
4742           }
4743         }
4744       }
4745       newNodesItVec.push_back( nIt );
4746     }
4747     // make new elements
4748     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4749   }
4750
4751   if ( theMakeWalls )
4752     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4753
4754   PGroupIDs newGroupIDs;
4755   if ( theMakeGroups )
4756     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4757
4758   return newGroupIDs;
4759 }
4760
4761
4762 //=======================================================================
4763 //function : CreateNode
4764 //purpose  :
4765 //=======================================================================
4766 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4767                                                   const double y,
4768                                                   const double z,
4769                                                   const double tolnode,
4770                                                   SMESH_SequenceOfNode& aNodes)
4771 {
4772   // myLastCreatedElems.Clear();
4773   // myLastCreatedNodes.Clear();
4774
4775   gp_Pnt P1(x,y,z);
4776   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4777
4778   // try to search in sequence of existing nodes
4779   // if aNodes.Length()>0 we 'nave to use given sequence
4780   // else - use all nodes of mesh
4781   if(aNodes.Length()>0) {
4782     int i;
4783     for(i=1; i<=aNodes.Length(); i++) {
4784       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4785       if(P1.Distance(P2)<tolnode)
4786         return aNodes.Value(i);
4787     }
4788   }
4789   else {
4790     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4791     while(itn->more()) {
4792       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4793       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4794       if(P1.Distance(P2)<tolnode)
4795         return aN;
4796     }
4797   }
4798
4799   // create new node and return it
4800   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4801   //myLastCreatedNodes.Append(NewNode);
4802   return NewNode;
4803 }
4804
4805
4806 //=======================================================================
4807 //function : ExtrusionSweep
4808 //purpose  :
4809 //=======================================================================
4810
4811 SMESH_MeshEditor::PGroupIDs
4812 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4813                                   const gp_Vec&       theStep,
4814                                   const int           theNbSteps,
4815                                   TElemOfElemListMap& newElemsMap,
4816                                   const bool          theMakeGroups,
4817                                   const int           theFlags,
4818                                   const double        theTolerance)
4819 {
4820   ExtrusParam aParams;
4821   aParams.myDir = gp_Dir(theStep);
4822   aParams.myNodes.Clear();
4823   aParams.mySteps = new TColStd_HSequenceOfReal;
4824   int i;
4825   for(i=1; i<=theNbSteps; i++)
4826     aParams.mySteps->Append(theStep.Magnitude());
4827
4828   return
4829     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4830 }
4831
4832
4833 //=======================================================================
4834 //function : ExtrusionSweep
4835 //purpose  :
4836 //=======================================================================
4837
4838 SMESH_MeshEditor::PGroupIDs
4839 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4840                                   ExtrusParam&        theParams,
4841                                   TElemOfElemListMap& newElemsMap,
4842                                   const bool          theMakeGroups,
4843                                   const int           theFlags,
4844                                   const double        theTolerance)
4845 {
4846   myLastCreatedElems.Clear();
4847   myLastCreatedNodes.Clear();
4848
4849   // source elements for each generated one
4850   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4851
4852   SMESHDS_Mesh* aMesh = GetMeshDS();
4853
4854   int nbsteps = theParams.mySteps->Length();
4855
4856   TNodeOfNodeListMap mapNewNodes;
4857   //TNodeOfNodeVecMap mapNewNodes;
4858   TElemOfVecOfNnlmiMap mapElemNewNodes;
4859   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4860
4861   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4862                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4863                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4864   // loop on theElems
4865   TIDSortedElemSet::iterator itElem;
4866   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4867     // check element type
4868     const SMDS_MeshElement* elem = *itElem;
4869     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4870       continue;
4871
4872     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4873     newNodesItVec.reserve( elem->NbNodes() );
4874
4875     // loop on elem nodes
4876     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4877     while ( itN->more() )
4878     {
4879       // check if a node has been already sweeped
4880       const SMDS_MeshNode* node = cast2Node( itN->next() );
4881       TNodeOfNodeListMap::iterator nIt =
4882         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4883       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4884       if ( listNewNodes.empty() )
4885       {
4886         // make new nodes
4887
4888         // check if we are to create medium nodes between corner ones
4889         bool needMediumNodes = false;
4890         if ( isQuadraticMesh )
4891         {
4892           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4893           while (it->more() && !needMediumNodes )
4894           {
4895             const SMDS_MeshElement* invElem = it->next();
4896             if ( invElem != elem && !theElems.count( invElem )) continue;
4897             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4898             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4899               needMediumNodes = true;
4900           }
4901         }
4902
4903         double coord[] = { node->X(), node->Y(), node->Z() };
4904         for ( int i = 0; i < nbsteps; i++ )
4905         {
4906           if ( needMediumNodes ) // create a medium node
4907           {
4908             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4909             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4910             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4911             if( theFlags & EXTRUSION_FLAG_SEW ) {
4912               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4913                                                          theTolerance, theParams.myNodes);
4914               listNewNodes.push_back( newNode );
4915             }
4916             else {
4917               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4918               myLastCreatedNodes.Append(newNode);
4919               srcNodes.Append( node );
4920               listNewNodes.push_back( newNode );
4921             }
4922           }
4923           // create a corner node
4924           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4925           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4926           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4927           if( theFlags & EXTRUSION_FLAG_SEW ) {
4928             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4929                                                        theTolerance, theParams.myNodes);
4930             listNewNodes.push_back( newNode );
4931           }
4932           else {
4933             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4934             myLastCreatedNodes.Append(newNode);
4935             srcNodes.Append( node );
4936             listNewNodes.push_back( newNode );
4937           }
4938         }
4939       }
4940       newNodesItVec.push_back( nIt );
4941     }
4942     // make new elements
4943     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4944   }
4945
4946   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4947     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4948   }
4949   PGroupIDs newGroupIDs;
4950   if ( theMakeGroups )
4951     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4952
4953   return newGroupIDs;
4954 }
4955
4956 //=======================================================================
4957 //function : ExtrusionAlongTrack
4958 //purpose  :
4959 //=======================================================================
4960 SMESH_MeshEditor::Extrusion_Error
4961 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4962                                        SMESH_subMesh*       theTrack,
4963                                        const SMDS_MeshNode* theN1,
4964                                        const bool           theHasAngles,
4965                                        list<double>&        theAngles,
4966                                        const bool           theLinearVariation,
4967                                        const bool           theHasRefPoint,
4968                                        const gp_Pnt&        theRefPoint,
4969                                        const bool           theMakeGroups)
4970 {
4971   MESSAGE("ExtrusionAlongTrack");
4972   myLastCreatedElems.Clear();
4973   myLastCreatedNodes.Clear();
4974
4975   int aNbE;
4976   std::list<double> aPrms;
4977   TIDSortedElemSet::iterator itElem;
4978
4979   gp_XYZ aGC;
4980   TopoDS_Edge aTrackEdge;
4981   TopoDS_Vertex aV1, aV2;
4982
4983   SMDS_ElemIteratorPtr aItE;
4984   SMDS_NodeIteratorPtr aItN;
4985   SMDSAbs_ElementType aTypeE;
4986
4987   TNodeOfNodeListMap mapNewNodes;
4988
4989   // 1. Check data
4990   aNbE = theElements.size();
4991   // nothing to do
4992   if ( !aNbE )
4993     return EXTR_NO_ELEMENTS;
4994
4995   // 1.1 Track Pattern
4996   ASSERT( theTrack );
4997
4998   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4999
5000   aItE = pSubMeshDS->GetElements();
5001   while ( aItE->more() ) {
5002     const SMDS_MeshElement* pE = aItE->next();
5003     aTypeE = pE->GetType();
5004     // Pattern must contain links only
5005     if ( aTypeE != SMDSAbs_Edge )
5006       return EXTR_PATH_NOT_EDGE;
5007   }
5008
5009   list<SMESH_MeshEditor_PathPoint> fullList;
5010
5011   const TopoDS_Shape& aS = theTrack->GetSubShape();
5012   // Sub-shape for the Pattern must be an Edge or Wire
5013   if( aS.ShapeType() == TopAbs_EDGE ) {
5014     aTrackEdge = TopoDS::Edge( aS );
5015     // the Edge must not be degenerated
5016     if ( BRep_Tool::Degenerated( aTrackEdge ) )
5017       return EXTR_BAD_PATH_SHAPE;
5018     TopExp::Vertices( aTrackEdge, aV1, aV2 );
5019     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
5020     const SMDS_MeshNode* aN1 = aItN->next();
5021     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
5022     const SMDS_MeshNode* aN2 = aItN->next();
5023     // starting node must be aN1 or aN2
5024     if ( !( aN1 == theN1 || aN2 == theN1 ) )
5025       return EXTR_BAD_STARTING_NODE;
5026     aItN = pSubMeshDS->GetNodes();
5027     while ( aItN->more() ) {
5028       const SMDS_MeshNode* pNode = aItN->next();
5029       const SMDS_EdgePosition* pEPos =
5030         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5031       double aT = pEPos->GetUParameter();
5032       aPrms.push_back( aT );
5033     }
5034     //Extrusion_Error err =
5035     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5036   } else if( aS.ShapeType() == TopAbs_WIRE ) {
5037     list< SMESH_subMesh* > LSM;
5038     TopTools_SequenceOfShape Edges;
5039     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
5040     while(itSM->more()) {
5041       SMESH_subMesh* SM = itSM->next();
5042       LSM.push_back(SM);
5043       const TopoDS_Shape& aS = SM->GetSubShape();
5044       Edges.Append(aS);
5045     }
5046     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5047     int startNid = theN1->GetID();
5048     TColStd_MapOfInteger UsedNums;
5049
5050     int NbEdges = Edges.Length();
5051     int i = 1;
5052     for(; i<=NbEdges; i++) {
5053       int k = 0;
5054       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5055       for(; itLSM!=LSM.end(); itLSM++) {
5056         k++;
5057         if(UsedNums.Contains(k)) continue;
5058         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5059         SMESH_subMesh* locTrack = *itLSM;
5060         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5061         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5062         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5063         const SMDS_MeshNode* aN1 = aItN->next();
5064         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5065         const SMDS_MeshNode* aN2 = aItN->next();
5066         // starting node must be aN1 or aN2
5067         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
5068         // 2. Collect parameters on the track edge
5069         aPrms.clear();
5070         aItN = locMeshDS->GetNodes();
5071         while ( aItN->more() ) {
5072           const SMDS_MeshNode* pNode = aItN->next();
5073           const SMDS_EdgePosition* pEPos =
5074             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5075           double aT = pEPos->GetUParameter();
5076           aPrms.push_back( aT );
5077         }
5078         list<SMESH_MeshEditor_PathPoint> LPP;
5079         //Extrusion_Error err =
5080         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
5081         LLPPs.push_back(LPP);
5082         UsedNums.Add(k);
5083         // update startN for search following egde
5084         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
5085         else startNid = aN1->GetID();
5086         break;
5087       }
5088     }
5089     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5090     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5091     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5092     for(; itPP!=firstList.end(); itPP++) {
5093       fullList.push_back( *itPP );
5094     }
5095     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5096     fullList.pop_back();
5097     itLLPP++;
5098     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5099       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5100       itPP = currList.begin();
5101       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5102       gp_Dir D1 = PP1.Tangent();
5103       gp_Dir D2 = PP2.Tangent();
5104       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5105                            (D1.Z()+D2.Z())/2 ) );
5106       PP1.SetTangent(Dnew);
5107       fullList.push_back(PP1);
5108       itPP++;
5109       for(; itPP!=firstList.end(); itPP++) {
5110         fullList.push_back( *itPP );
5111       }
5112       PP1 = fullList.back();
5113       fullList.pop_back();
5114     }
5115     // if wire not closed
5116     fullList.push_back(PP1);
5117     // else ???
5118   }
5119   else {
5120     return EXTR_BAD_PATH_SHAPE;
5121   }
5122
5123   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5124                           theHasRefPoint, theRefPoint, theMakeGroups);
5125 }
5126
5127
5128 //=======================================================================
5129 //function : ExtrusionAlongTrack
5130 //purpose  :
5131 //=======================================================================
5132 SMESH_MeshEditor::Extrusion_Error
5133 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
5134                                        SMESH_Mesh*          theTrack,
5135                                        const SMDS_MeshNode* theN1,
5136                                        const bool           theHasAngles,
5137                                        list<double>&        theAngles,
5138                                        const bool           theLinearVariation,
5139                                        const bool           theHasRefPoint,
5140                                        const gp_Pnt&        theRefPoint,
5141                                        const bool           theMakeGroups)
5142 {
5143   myLastCreatedElems.Clear();
5144   myLastCreatedNodes.Clear();
5145
5146   int aNbE;
5147   std::list<double> aPrms;
5148   TIDSortedElemSet::iterator itElem;
5149
5150   gp_XYZ aGC;
5151   TopoDS_Edge aTrackEdge;
5152   TopoDS_Vertex aV1, aV2;
5153
5154   SMDS_ElemIteratorPtr aItE;
5155   SMDS_NodeIteratorPtr aItN;
5156   SMDSAbs_ElementType aTypeE;
5157
5158   TNodeOfNodeListMap mapNewNodes;
5159
5160   // 1. Check data
5161   aNbE = theElements.size();
5162   // nothing to do
5163   if ( !aNbE )
5164     return EXTR_NO_ELEMENTS;
5165
5166   // 1.1 Track Pattern
5167   ASSERT( theTrack );
5168
5169   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
5170
5171   aItE = pMeshDS->elementsIterator();
5172   while ( aItE->more() ) {
5173     const SMDS_MeshElement* pE = aItE->next();
5174     aTypeE = pE->GetType();
5175     // Pattern must contain links only
5176     if ( aTypeE != SMDSAbs_Edge )
5177       return EXTR_PATH_NOT_EDGE;
5178   }
5179
5180   list<SMESH_MeshEditor_PathPoint> fullList;
5181
5182   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
5183
5184   if ( !theTrack->HasShapeToMesh() ) {
5185     //Mesh without shape
5186     const SMDS_MeshNode* currentNode = NULL;
5187     const SMDS_MeshNode* prevNode = theN1;
5188     std::vector<const SMDS_MeshNode*> aNodesList;
5189     aNodesList.push_back(theN1);
5190     int nbEdges = 0, conn=0;
5191     const SMDS_MeshElement* prevElem = NULL;
5192     const SMDS_MeshElement* currentElem = NULL;
5193     int totalNbEdges = theTrack->NbEdges();
5194     SMDS_ElemIteratorPtr nIt;
5195
5196     //check start node
5197     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
5198       return EXTR_BAD_STARTING_NODE;
5199     }
5200
5201     conn = nbEdgeConnectivity(theN1);
5202     if(conn > 2)
5203       return EXTR_PATH_NOT_EDGE;
5204
5205     aItE = theN1->GetInverseElementIterator();
5206     prevElem = aItE->next();
5207     currentElem = prevElem;
5208     //Get all nodes
5209     if(totalNbEdges == 1 ) {
5210       nIt = currentElem->nodesIterator();
5211       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5212       if(currentNode == prevNode)
5213         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5214       aNodesList.push_back(currentNode);
5215     } else {
5216       nIt = currentElem->nodesIterator();
5217       while( nIt->more() ) {
5218         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5219         if(currentNode == prevNode)
5220           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5221         aNodesList.push_back(currentNode);
5222
5223         //case of the closed mesh
5224         if(currentNode == theN1) {
5225           nbEdges++;
5226           break;
5227         }
5228
5229         conn = nbEdgeConnectivity(currentNode);
5230         if(conn > 2) {
5231           return EXTR_PATH_NOT_EDGE;
5232         }else if( conn == 1 && nbEdges > 0 ) {
5233           //End of the path
5234           nbEdges++;
5235           break;
5236         }else {
5237           prevNode = currentNode;
5238           aItE = currentNode->GetInverseElementIterator();
5239           currentElem = aItE->next();
5240           if( currentElem  == prevElem)
5241             currentElem = aItE->next();
5242           nIt = currentElem->nodesIterator();
5243           prevElem = currentElem;
5244           nbEdges++;
5245         }
5246       }
5247     }
5248
5249     if(nbEdges != totalNbEdges)
5250       return EXTR_PATH_NOT_EDGE;
5251
5252     TopTools_SequenceOfShape Edges;
5253     double x1,x2,y1,y2,z1,z2;
5254     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5255     int startNid = theN1->GetID();
5256     for(int i = 1; i < aNodesList.size(); i++) {
5257       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
5258       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
5259       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
5260       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));
5261       list<SMESH_MeshEditor_PathPoint> LPP;
5262       aPrms.clear();
5263       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
5264       LLPPs.push_back(LPP);
5265       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
5266       else startNid = aNodesList[i-1]->GetID();
5267
5268     }
5269
5270     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5271     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5272     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5273     for(; itPP!=firstList.end(); itPP++) {
5274       fullList.push_back( *itPP );
5275     }
5276
5277     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5278     SMESH_MeshEditor_PathPoint PP2;
5279     fullList.pop_back();
5280     itLLPP++;
5281     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5282       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5283       itPP = currList.begin();
5284       PP2 = currList.front();
5285       gp_Dir D1 = PP1.Tangent();
5286       gp_Dir D2 = PP2.Tangent();
5287       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5288                            (D1.Z()+D2.Z())/2 ) );
5289       PP1.SetTangent(Dnew);
5290       fullList.push_back(PP1);
5291       itPP++;
5292       for(; itPP!=currList.end(); itPP++) {
5293         fullList.push_back( *itPP );
5294       }
5295       PP1 = fullList.back();
5296       fullList.pop_back();
5297     }
5298     fullList.push_back(PP1);
5299
5300   } // Sub-shape for the Pattern must be an Edge or Wire
5301   else if( aS.ShapeType() == TopAbs_EDGE ) {
5302     aTrackEdge = TopoDS::Edge( aS );
5303     // the Edge must not be degenerated
5304     if ( BRep_Tool::Degenerated( aTrackEdge ) )
5305       return EXTR_BAD_PATH_SHAPE;
5306     TopExp::Vertices( aTrackEdge, aV1, aV2 );
5307     const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS );
5308     const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS );
5309     // starting node must be aN1 or aN2
5310     if ( !( aN1 == theN1 || aN2 == theN1 ) )
5311       return EXTR_BAD_STARTING_NODE;
5312     aItN = pMeshDS->nodesIterator();
5313     while ( aItN->more() ) {
5314       const SMDS_MeshNode* pNode = aItN->next();
5315       if( pNode==aN1 || pNode==aN2 ) continue;
5316       const SMDS_EdgePosition* pEPos =
5317         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5318       double aT = pEPos->GetUParameter();
5319       aPrms.push_back( aT );
5320     }
5321     //Extrusion_Error err =
5322     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5323   }
5324   else if( aS.ShapeType() == TopAbs_WIRE ) {
5325     list< SMESH_subMesh* > LSM;
5326     TopTools_SequenceOfShape Edges;
5327     TopExp_Explorer eExp(aS, TopAbs_EDGE);
5328     for(; eExp.More(); eExp.Next()) {
5329       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5330       if( BRep_Tool::Degenerated(E) ) continue;
5331       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5332       if(SM) {
5333         LSM.push_back(SM);
5334         Edges.Append(E);
5335       }
5336     }
5337     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5338     TopoDS_Vertex aVprev;
5339     TColStd_MapOfInteger UsedNums;
5340     int NbEdges = Edges.Length();
5341     int i = 1;
5342     for(; i<=NbEdges; i++) {
5343       int k = 0;
5344       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5345       for(; itLSM!=LSM.end(); itLSM++) {
5346         k++;
5347         if(UsedNums.Contains(k)) continue;
5348         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5349         SMESH_subMesh* locTrack = *itLSM;
5350         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5351         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5352         bool aN1isOK = false, aN2isOK = false;
5353         if ( aVprev.IsNull() ) {
5354           // if previous vertex is not yet defined, it means that we in the beginning of wire
5355           // and we have to find initial vertex corresponding to starting node theN1
5356           const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS );
5357           const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS );
5358           // starting node must be aN1 or aN2
5359           aN1isOK = ( aN1 && aN1 == theN1 );
5360           aN2isOK = ( aN2 && aN2 == theN1 );
5361         }
5362         else {
5363           // we have specified ending vertex of the previous edge on the previous iteration
5364           // and we have just to check that it corresponds to any vertex in current segment
5365           aN1isOK = aVprev.IsSame( aV1 );
5366           aN2isOK = aVprev.IsSame( aV2 );
5367         }
5368         if ( !aN1isOK && !aN2isOK ) continue;
5369         // 2. Collect parameters on the track edge
5370         aPrms.clear();
5371         aItN = locMeshDS->GetNodes();
5372         while ( aItN->more() ) {
5373           const SMDS_MeshNode*     pNode = aItN->next();
5374           const SMDS_EdgePosition* pEPos =
5375             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5376           double aT = pEPos->GetUParameter();
5377           aPrms.push_back( aT );
5378         }
5379         list<SMESH_MeshEditor_PathPoint> LPP;
5380         //Extrusion_Error err =
5381         MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
5382         LLPPs.push_back(LPP);
5383         UsedNums.Add(k);
5384         // update startN for search following egde
5385         if ( aN1isOK ) aVprev = aV2;
5386         else           aVprev = aV1;
5387         break;
5388       }
5389     }
5390     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5391     list<SMESH_MeshEditor_PathPoint>& firstList = *itLLPP;
5392     fullList.splice( fullList.end(), firstList );
5393
5394     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5395     fullList.pop_back();
5396     itLLPP++;
5397     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5398       list<SMESH_MeshEditor_PathPoint>& currList = *itLLPP;
5399       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5400       gp_Dir D1 = PP1.Tangent();
5401       gp_Dir D2 = PP2.Tangent();
5402       gp_Dir Dnew( ( D1.XYZ() + D2.XYZ() ) / 2 );
5403       PP1.SetTangent(Dnew);
5404       fullList.push_back(PP1);
5405       fullList.splice( fullList.end(), currList, ++currList.begin(), currList.end() );
5406       PP1 = fullList.back();
5407       fullList.pop_back();
5408     }
5409     // if wire not closed
5410     fullList.push_back(PP1);
5411     // else ???
5412   }
5413   else {
5414     return EXTR_BAD_PATH_SHAPE;
5415   }
5416
5417   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5418                           theHasRefPoint, theRefPoint, theMakeGroups);
5419 }
5420
5421
5422 //=======================================================================
5423 //function : MakeEdgePathPoints
5424 //purpose  : auxilary for ExtrusionAlongTrack
5425 //=======================================================================
5426 SMESH_MeshEditor::Extrusion_Error
5427 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>&                aPrms,
5428                                      const TopoDS_Edge&                aTrackEdge,
5429                                      bool                              FirstIsStart,
5430                                      list<SMESH_MeshEditor_PathPoint>& LPP)
5431 {
5432   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5433   aTolVec=1.e-7;
5434   aTolVec2=aTolVec*aTolVec;
5435   double aT1, aT2;
5436   TopoDS_Vertex aV1, aV2;
5437   TopExp::Vertices( aTrackEdge, aV1, aV2 );
5438   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5439   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5440   // 2. Collect parameters on the track edge
5441   aPrms.push_front( aT1 );
5442   aPrms.push_back( aT2 );
5443   // sort parameters
5444   aPrms.sort();
5445   if( FirstIsStart ) {
5446     if ( aT1 > aT2 ) {
5447       aPrms.reverse();
5448     }
5449   }
5450   else {
5451     if ( aT2 > aT1 ) {
5452       aPrms.reverse();
5453     }
5454   }
5455   // 3. Path Points
5456   SMESH_MeshEditor_PathPoint aPP;
5457   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5458   std::list<double>::iterator aItD = aPrms.begin();
5459   for(; aItD != aPrms.end(); ++aItD) {
5460     double aT = *aItD;
5461     gp_Pnt aP3D;
5462     gp_Vec aVec;
5463     aC3D->D1( aT, aP3D, aVec );
5464     aL2 = aVec.SquareMagnitude();
5465     if ( aL2 < aTolVec2 )
5466       return EXTR_CANT_GET_TANGENT;
5467     gp_Dir aTgt( aVec );
5468     aPP.SetPnt( aP3D );
5469     aPP.SetTangent( aTgt );
5470     aPP.SetParameter( aT );
5471     LPP.push_back(aPP);
5472   }
5473   return EXTR_OK;
5474 }
5475
5476
5477 //=======================================================================
5478 //function : MakeExtrElements
5479 //purpose  : auxilary for ExtrusionAlongTrack
5480 //=======================================================================
5481 SMESH_MeshEditor::Extrusion_Error
5482 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&                 theElements,
5483                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5484                                    const bool                        theHasAngles,
5485                                    list<double>&                     theAngles,
5486                                    const bool                        theLinearVariation,
5487                                    const bool                        theHasRefPoint,
5488                                    const gp_Pnt&                     theRefPoint,
5489                                    const bool                        theMakeGroups)
5490 {
5491   const int aNbTP = fullList.size();
5492   // Angles
5493   if( theHasAngles && !theAngles.empty() && theLinearVariation )
5494     LinearAngleVariation(aNbTP-1, theAngles);
5495   // fill vector of path points with angles
5496   vector<SMESH_MeshEditor_PathPoint> aPPs;
5497   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5498   list<double>::iterator                 itAngles = theAngles.begin();
5499   aPPs.push_back( *itPP++ );
5500   for( ; itPP != fullList.end(); itPP++) {
5501     aPPs.push_back( *itPP );
5502     if ( theHasAngles && itAngles != theAngles.end() )
5503       aPPs.back().SetAngle( *itAngles );
5504   }
5505
5506   TNodeOfNodeListMap   mapNewNodes;
5507   TElemOfVecOfNnlmiMap mapElemNewNodes;
5508   TElemOfElemListMap   newElemsMap;
5509   TIDSortedElemSet::iterator itElem;
5510   // source elements for each generated one
5511   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5512
5513   // 3. Center of rotation aV0
5514   gp_Pnt aV0 = theRefPoint;
5515   if ( !theHasRefPoint )
5516   {
5517     gp_XYZ aGC( 0.,0.,0. );
5518     TIDSortedElemSet newNodes;
5519
5520     itElem = theElements.begin();
5521     for ( ; itElem != theElements.end(); itElem++ ) {
5522       const SMDS_MeshElement* elem = *itElem;
5523
5524       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5525       while ( itN->more() ) {
5526         const SMDS_MeshElement* node = itN->next();
5527         if ( newNodes.insert( node ).second )
5528           aGC += SMESH_TNodeXYZ( node );
5529       }
5530     }
5531     aGC /= newNodes.size();
5532     aV0.SetXYZ( aGC );
5533   } // if (!theHasRefPoint) {
5534
5535   // 4. Processing the elements
5536   SMESHDS_Mesh* aMesh = GetMeshDS();
5537
5538   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5539     // check element type
5540     const SMDS_MeshElement* elem = *itElem;
5541     SMDSAbs_ElementType   aTypeE = elem->GetType();
5542     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5543       continue;
5544
5545     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5546     newNodesItVec.reserve( elem->NbNodes() );
5547
5548     // loop on elem nodes
5549     int nodeIndex = -1;
5550     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5551     while ( itN->more() )
5552     {
5553       ++nodeIndex;
5554       // check if a node has been already processed
5555       const SMDS_MeshNode* node =
5556         static_cast<const SMDS_MeshNode*>( itN->next() );
5557       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5558       if ( nIt == mapNewNodes.end() ) {
5559         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5560         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5561
5562         // make new nodes
5563         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5564         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5565         gp_Ax1 anAx1, anAxT1T0;
5566         gp_Dir aDT1x, aDT0x, aDT1T0;
5567
5568         aTolAng=1.e-4;
5569
5570         aV0x = aV0;
5571         aPN0 = SMESH_TNodeXYZ( node );
5572
5573         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5574         aP0x = aPP0.Pnt();
5575         aDT0x= aPP0.Tangent();
5576         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5577
5578         for ( int j = 1; j < aNbTP; ++j ) {
5579           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5580           aP1x     = aPP1.Pnt();
5581           aDT1x    = aPP1.Tangent();
5582           aAngle1x = aPP1.Angle();
5583
5584           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5585           // Translation
5586           gp_Vec aV01x( aP0x, aP1x );
5587           aTrsf.SetTranslation( aV01x );
5588
5589           // traslated point
5590           aV1x = aV0x.Transformed( aTrsf );
5591           aPN1 = aPN0.Transformed( aTrsf );
5592
5593           // rotation 1 [ T1,T0 ]
5594           aAngleT1T0=-aDT1x.Angle( aDT0x );
5595           if (fabs(aAngleT1T0) > aTolAng) {
5596             aDT1T0=aDT1x^aDT0x;
5597             anAxT1T0.SetLocation( aV1x );
5598             anAxT1T0.SetDirection( aDT1T0 );
5599             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5600
5601             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5602           }
5603
5604           // rotation 2
5605           if ( theHasAngles ) {
5606             anAx1.SetLocation( aV1x );
5607             anAx1.SetDirection( aDT1x );
5608             aTrsfRot.SetRotation( anAx1, aAngle1x );
5609
5610             aPN1 = aPN1.Transformed( aTrsfRot );
5611           }
5612
5613           // make new node
5614           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5615           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5616             // create additional node
5617             double x = ( aPN1.X() + aPN0.X() )/2.;
5618             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5619             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5620             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5621             myLastCreatedNodes.Append(newNode);
5622             srcNodes.Append( node );
5623             listNewNodes.push_back( newNode );
5624           }
5625           const SMDS_MeshNode* newNode = aMesh->AddNode( aPN1.X(), aPN1.Y(), aPN1.Z() );
5626           myLastCreatedNodes.Append(newNode);
5627           srcNodes.Append( node );
5628           listNewNodes.push_back( newNode );
5629
5630           aPN0 = aPN1;
5631           aP0x = aP1x;
5632           aV0x = aV1x;
5633           aDT0x = aDT1x;
5634         }
5635       }
5636
5637       else {
5638         // if current elem is quadratic and current node is not medium
5639         // we have to check - may be it is needed to insert additional nodes
5640         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5641           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5642           if(listNewNodes.size()==aNbTP-1) {
5643             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5644             gp_XYZ P(node->X(), node->Y(), node->Z());
5645             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5646             int i;
5647             for(i=0; i<aNbTP-1; i++) {
5648               const SMDS_MeshNode* N = *it;
5649               double x = ( N->X() + P.X() )/2.;
5650               double y = ( N->Y() + P.Y() )/2.;
5651               double z = ( N->Z() + P.Z() )/2.;
5652               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5653               srcNodes.Append( node );
5654               myLastCreatedNodes.Append(newN);
5655               aNodes[2*i] = newN;
5656               aNodes[2*i+1] = N;
5657               P = gp_XYZ(N->X(),N->Y(),N->Z());
5658             }
5659             listNewNodes.clear();
5660             for(i=0; i<2*(aNbTP-1); i++) {
5661               listNewNodes.push_back(aNodes[i]);
5662             }
5663           }
5664         }
5665       }
5666
5667       newNodesItVec.push_back( nIt );
5668     }
5669     // make new elements
5670     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5671     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5672     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5673   }
5674
5675   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5676
5677   if ( theMakeGroups )
5678     generateGroups( srcNodes, srcElems, "extruded");
5679
5680   return EXTR_OK;
5681 }
5682
5683
5684 //=======================================================================
5685 //function : LinearAngleVariation
5686 //purpose  : auxilary for ExtrusionAlongTrack
5687 //=======================================================================
5688 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5689                                             list<double>& Angles)
5690 {
5691   int nbAngles = Angles.size();
5692   if( nbSteps > nbAngles ) {
5693     vector<double> theAngles(nbAngles);
5694     list<double>::iterator it = Angles.begin();
5695     int i = -1;
5696     for(; it!=Angles.end(); it++) {
5697       i++;
5698       theAngles[i] = (*it);
5699     }
5700     list<double> res;
5701     double rAn2St = double( nbAngles ) / double( nbSteps );
5702     double angPrev = 0, angle;
5703     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5704       double angCur = rAn2St * ( iSt+1 );
5705       double angCurFloor  = floor( angCur );
5706       double angPrevFloor = floor( angPrev );
5707       if ( angPrevFloor == angCurFloor )
5708         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5709       else {
5710         int iP = int( angPrevFloor );
5711         double angPrevCeil = ceil(angPrev);
5712         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5713
5714         int iC = int( angCurFloor );
5715         if ( iC < nbAngles )
5716           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5717
5718         iP = int( angPrevCeil );
5719         while ( iC-- > iP )
5720           angle += theAngles[ iC ];
5721       }
5722       res.push_back(angle);
5723       angPrev = angCur;
5724     }
5725     Angles.clear();
5726     it = res.begin();
5727     for(; it!=res.end(); it++)
5728       Angles.push_back( *it );
5729   }
5730 }
5731
5732
5733 //================================================================================
5734 /*!
5735  * \brief Move or copy theElements applying theTrsf to their nodes
5736  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5737  *  \param theTrsf - transformation to apply
5738  *  \param theCopy - if true, create translated copies of theElems
5739  *  \param theMakeGroups - if true and theCopy, create translated groups
5740  *  \param theTargetMesh - mesh to copy translated elements into
5741  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5742  */
5743 //================================================================================
5744
5745 SMESH_MeshEditor::PGroupIDs
5746 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5747                              const gp_Trsf&     theTrsf,
5748                              const bool         theCopy,
5749                              const bool         theMakeGroups,
5750                              SMESH_Mesh*        theTargetMesh)
5751 {
5752   myLastCreatedElems.Clear();
5753   myLastCreatedNodes.Clear();
5754
5755   bool needReverse = false;
5756   string groupPostfix;
5757   switch ( theTrsf.Form() ) {
5758   case gp_PntMirror:
5759     MESSAGE("gp_PntMirror");
5760     needReverse = true;
5761     groupPostfix = "mirrored";
5762     break;
5763   case gp_Ax1Mirror:
5764     MESSAGE("gp_Ax1Mirror");
5765     groupPostfix = "mirrored";
5766     break;
5767   case gp_Ax2Mirror:
5768     MESSAGE("gp_Ax2Mirror");
5769     needReverse = true;
5770     groupPostfix = "mirrored";
5771     break;
5772   case gp_Rotation:
5773     MESSAGE("gp_Rotation");
5774     groupPostfix = "rotated";
5775     break;
5776   case gp_Translation:
5777     MESSAGE("gp_Translation");
5778     groupPostfix = "translated";
5779     break;
5780   case gp_Scale:
5781     MESSAGE("gp_Scale");
5782     groupPostfix = "scaled";
5783     break;
5784   case gp_CompoundTrsf: // different scale by axis
5785     MESSAGE("gp_CompoundTrsf");
5786     groupPostfix = "scaled";
5787     break;
5788   default:
5789     MESSAGE("default");
5790     needReverse = false;
5791     groupPostfix = "transformed";
5792   }
5793
5794   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5795   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5796   SMESHDS_Mesh* aMesh    = GetMeshDS();
5797
5798
5799   // map old node to new one
5800   TNodeNodeMap nodeMap;
5801
5802   // elements sharing moved nodes; those of them which have all
5803   // nodes mirrored but are not in theElems are to be reversed
5804   TIDSortedElemSet inverseElemSet;
5805
5806   // source elements for each generated one
5807   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5808
5809   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5810   TIDSortedElemSet orphanNode;
5811
5812   if ( theElems.empty() ) // transform the whole mesh
5813   {
5814     // add all elements
5815     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5816     while ( eIt->more() ) theElems.insert( eIt->next() );
5817     // add orphan nodes
5818     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5819     while ( nIt->more() )
5820     {
5821       const SMDS_MeshNode* node = nIt->next();
5822       if ( node->NbInverseElements() == 0)
5823         orphanNode.insert( node );
5824     }
5825   }
5826
5827   // loop on elements to transform nodes : first orphan nodes then elems
5828   TIDSortedElemSet::iterator itElem;
5829   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5830   for (int i=0; i<2; i++)
5831   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5832     const SMDS_MeshElement* elem = *itElem;
5833     if ( !elem )
5834       continue;
5835
5836     // loop on elem nodes
5837     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5838     while ( itN->more() ) {
5839
5840       const SMDS_MeshNode* node = cast2Node( itN->next() );
5841       // check if a node has been already transformed
5842       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5843         nodeMap.insert( make_pair ( node, node ));
5844       if ( !n2n_isnew.second )
5845         continue;
5846
5847       double coord[3];
5848       coord[0] = node->X();
5849       coord[1] = node->Y();
5850       coord[2] = node->Z();
5851       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5852       if ( theTargetMesh ) {
5853         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5854         n2n_isnew.first->second = newNode;
5855         myLastCreatedNodes.Append(newNode);
5856         srcNodes.Append( node );
5857       }
5858       else if ( theCopy ) {
5859         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5860         n2n_isnew.first->second = newNode;
5861         myLastCreatedNodes.Append(newNode);
5862         srcNodes.Append( node );
5863       }
5864       else {
5865         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5866         // node position on shape becomes invalid
5867         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5868           ( SMDS_SpacePosition::originSpacePosition() );
5869       }
5870
5871       // keep inverse elements
5872       if ( !theCopy && !theTargetMesh && needReverse ) {
5873         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5874         while ( invElemIt->more() ) {
5875           const SMDS_MeshElement* iel = invElemIt->next();
5876           inverseElemSet.insert( iel );
5877         }
5878       }
5879     }
5880   }
5881
5882   // either create new elements or reverse mirrored ones
5883   if ( !theCopy && !needReverse && !theTargetMesh )
5884     return PGroupIDs();
5885
5886   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5887   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5888     theElems.insert( *invElemIt );
5889
5890   // Replicate or reverse elements
5891
5892   std::vector<int> iForw;
5893   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5894   {
5895     const SMDS_MeshElement* elem = *itElem;
5896     if ( !elem ) continue;
5897
5898     SMDSAbs_GeometryType geomType = elem->GetGeomType();
5899     int                  nbNodes  = elem->NbNodes();
5900     if ( geomType == SMDSGeom_NONE ) continue; // node
5901
5902     switch ( geomType ) {
5903
5904     case SMDSGeom_POLYGON:  // ---------------------- polygon
5905       {
5906         vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5907         int iNode = 0;
5908         SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5909         while (itN->more()) {
5910           const SMDS_MeshNode* node =
5911             static_cast<const SMDS_MeshNode*>(itN->next());
5912           TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5913           if (nodeMapIt == nodeMap.end())
5914             break; // not all nodes transformed
5915           if (needReverse) {
5916             // reverse mirrored faces and volumes
5917             poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5918           } else {
5919             poly_nodes[iNode] = (*nodeMapIt).second;
5920           }
5921           iNode++;
5922         }
5923         if ( iNode != nbNodes )
5924           continue; // not all nodes transformed
5925
5926         if ( theTargetMesh ) {
5927           myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5928           srcElems.Append( elem );
5929         }
5930         else if ( theCopy ) {
5931           myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5932           srcElems.Append( elem );
5933         }
5934         else {
5935           aMesh->ChangePolygonNodes(elem, poly_nodes);
5936         }
5937       }
5938       break;
5939
5940     case SMDSGeom_POLYHEDRA:  // ------------------ polyhedral volume
5941       {
5942         const SMDS_VtkVolume* aPolyedre =
5943           dynamic_cast<const SMDS_VtkVolume*>( elem );
5944         if (!aPolyedre) {
5945           MESSAGE("Warning: bad volumic element");
5946           continue;
5947         }
5948
5949         vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
5950         vector<int> quantities; quantities.reserve( nbNodes );
5951
5952         bool allTransformed = true;
5953         int nbFaces = aPolyedre->NbFaces();
5954         for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5955           int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5956           for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5957             const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5958             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5959             if (nodeMapIt == nodeMap.end()) {
5960               allTransformed = false; // not all nodes transformed
5961             } else {
5962               poly_nodes.push_back((*nodeMapIt).second);
5963             }
5964             if ( needReverse && allTransformed )
5965               std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
5966           }
5967           quantities.push_back(nbFaceNodes);
5968         }
5969         if ( !allTransformed )
5970           continue; // not all nodes transformed
5971
5972         if ( theTargetMesh ) {
5973           myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5974           srcElems.Append( elem );
5975         }
5976         else if ( theCopy ) {
5977           myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5978           srcElems.Append( elem );
5979         }
5980         else {
5981           aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5982         }
5983       }
5984       break;
5985
5986     case SMDSGeom_BALL: // -------------------- Ball
5987       {
5988         if ( !theCopy && !theTargetMesh ) continue;
5989
5990         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) );
5991         if (nodeMapIt == nodeMap.end())
5992           continue; // not all nodes transformed
5993
5994         double diameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
5995         if ( theTargetMesh ) {
5996           myLastCreatedElems.Append(aTgtMesh->AddBall( nodeMapIt->second, diameter ));
5997           srcElems.Append( elem );
5998         }
5999         else {
6000           myLastCreatedElems.Append(aMesh->AddBall( nodeMapIt->second, diameter ));
6001           srcElems.Append( elem );
6002         }
6003       }
6004       break;
6005
6006     default: // ----------------------- Regular elements
6007
6008       while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
6009       const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
6010       const std::vector<int>& i = needReverse ? iRev : iForw;
6011
6012       // find transformed nodes
6013       vector<const SMDS_MeshNode*> nodes(nbNodes);
6014       int iNode = 0;
6015       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6016       while ( itN->more() ) {
6017         const SMDS_MeshNode* node =
6018           static_cast<const SMDS_MeshNode*>( itN->next() );
6019         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
6020         if ( nodeMapIt == nodeMap.end() )
6021           break; // not all nodes transformed
6022         nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
6023       }
6024       if ( iNode != nbNodes )
6025         continue; // not all nodes transformed
6026
6027       if ( theTargetMesh ) {
6028         if ( SMDS_MeshElement* copy =
6029              targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
6030           myLastCreatedElems.Append( copy );
6031           srcElems.Append( elem );
6032         }
6033       }
6034       else if ( theCopy ) {
6035         if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
6036           srcElems.Append( elem );
6037       }
6038       else {
6039         // reverse element as it was reversed by transformation
6040         if ( nbNodes > 2 )
6041           aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
6042       }
6043     } // switch ( geomType )
6044
6045   } // loop on elements
6046
6047   PGroupIDs newGroupIDs;
6048
6049   if ( ( theMakeGroups && theCopy ) ||
6050        ( theMakeGroups && theTargetMesh ) )
6051     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
6052
6053   return newGroupIDs;
6054 }
6055
6056 //=======================================================================
6057 /*!
6058  * \brief Create groups of elements made during transformation
6059  * \param nodeGens - nodes making corresponding myLastCreatedNodes
6060  * \param elemGens - elements making corresponding myLastCreatedElems
6061  * \param postfix - to append to names of new groups
6062  */
6063 //=======================================================================
6064
6065 SMESH_MeshEditor::PGroupIDs
6066 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
6067                                  const SMESH_SequenceOfElemPtr& elemGens,
6068                                  const std::string&             postfix,
6069                                  SMESH_Mesh*                    targetMesh)
6070 {
6071   PGroupIDs newGroupIDs( new list<int> );
6072   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6073
6074   // Sort existing groups by types and collect their names
6075
6076   // to store an old group and a generated new ones
6077   using boost::tuple;
6078   using boost::make_tuple;
6079   typedef tuple< SMESHDS_GroupBase*, SMESHDS_Group*, SMESHDS_Group* > TOldNewGroup;
6080   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6081   vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups
6082   // group names
6083   set< string > groupNames;
6084
6085   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6086   if ( !groupIt->more() ) return newGroupIDs;
6087
6088   int newGroupID = mesh->GetGroupIds().back()+1;
6089   while ( groupIt->more() )
6090   {
6091     SMESH_Group * group = groupIt->next();
6092     if ( !group ) continue;
6093     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6094     if ( !groupDS || groupDS->IsEmpty() ) continue;
6095     groupNames.insert    ( group->GetName() );
6096     groupDS->SetStoreName( group->GetName() );
6097     const SMDSAbs_ElementType type = groupDS->GetType();
6098     SMESHDS_Group* newGroup    = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
6099     SMESHDS_Group* newTopGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
6100     groupsByType[ type ].push_back( make_tuple( groupDS, newGroup, newTopGroup ));
6101     orderedOldNewGroups.push_back( & groupsByType[ type ].back() );
6102   }
6103
6104   // Loop on nodes and elements to add them in new groups
6105
6106   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6107   {
6108     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6109     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6110     if ( gens.Length() != elems.Length() )
6111       throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args");
6112
6113     // loop on created elements
6114     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6115     {
6116       const SMDS_MeshElement* sourceElem = gens( iElem );
6117       if ( !sourceElem ) {
6118         MESSAGE("generateGroups(): NULL source element");
6119         continue;
6120       }
6121       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6122       if ( groupsOldNew.empty() ) { // no groups of this type at all
6123         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6124           ++iElem; // skip all elements made by sourceElem
6125         continue;
6126       }
6127       // collect all elements made by the iElem-th sourceElem
6128       list< const SMDS_MeshElement* > resultElems;
6129       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6130         if ( resElem != sourceElem )
6131           resultElems.push_back( resElem );
6132       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6133         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6134           if ( resElem != sourceElem )
6135             resultElems.push_back( resElem );
6136
6137       // there must be a top element
6138       const SMDS_MeshElement* topElem = 0;
6139       if ( isNodes )
6140       {
6141         topElem = resultElems.back();
6142         resultElems.pop_back();
6143       }
6144       else
6145       {
6146         list< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin();
6147         for ( ; resElemIt != resultElems.rend() ; ++resElemIt )
6148           if ( (*resElemIt)->GetType() == sourceElem->GetType() )
6149           {
6150             topElem = *resElemIt;
6151             resultElems.erase( --(resElemIt.base()) ); // erase *resElemIt
6152             break;
6153           }
6154       }
6155
6156       // add resultElems to groups originted from ones the sourceElem belongs to
6157       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6158       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6159       {
6160         SMESHDS_GroupBase* oldGroup = gOldNew->get<0>();
6161         if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup
6162         {
6163           // fill in a new group
6164           SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup();
6165           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6166           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6167             newGroup.Add( *resElemIt );
6168
6169           // fill a "top" group
6170           if ( topElem )
6171           {
6172             SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup();
6173             newTopGroup.Add( topElem );
6174           }
6175         }
6176       }
6177     } // loop on created elements
6178   }// loop on nodes and elements
6179
6180   // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups
6181
6182   list<int> topGrouIds;
6183   for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i )
6184   {
6185     SMESHDS_GroupBase* oldGroupDS =   orderedOldNewGroups[i]->get<0>();
6186     SMESHDS_Group*   newGroups[2] = { orderedOldNewGroups[i]->get<1>(),
6187                                       orderedOldNewGroups[i]->get<2>() };
6188     const int nbNewGroups = !newGroups[0]->IsEmpty() + !newGroups[1]->IsEmpty();
6189     for ( int is2nd = 0; is2nd < 2; ++is2nd )
6190     {
6191       SMESHDS_Group* newGroupDS = newGroups[ is2nd ];
6192       if ( newGroupDS->IsEmpty() )
6193       {
6194         mesh->GetMeshDS()->RemoveGroup( newGroupDS );
6195       }
6196       else
6197       {
6198         // set group type
6199         newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
6200
6201         // make a name
6202         const bool isTop = ( nbNewGroups == 2 &&
6203                              newGroupDS->GetType() == oldGroupDS->GetType() &&
6204                              is2nd );
6205
6206         string name = oldGroupDS->GetStoreName();
6207         if ( !targetMesh ) {
6208           string suffix = ( isTop ? "top": postfix.c_str() );
6209           name += "_";
6210           name += suffix;
6211           int nb = 1;
6212           while ( !groupNames.insert( name ).second ) // name exists
6213             name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << suffix << "_" << nb++;
6214         }
6215         else if ( isTop ) {
6216           name += "_top";
6217         }
6218         newGroupDS->SetStoreName( name.c_str() );
6219
6220         // make a SMESH_Groups
6221         mesh->AddGroup( newGroupDS );
6222         if ( isTop )
6223           topGrouIds.push_back( newGroupDS->GetID() );
6224         else
6225           newGroupIDs->push_back( newGroupDS->GetID() );
6226       }
6227     }
6228   }
6229   newGroupIDs->splice( newGroupIDs->end(), topGrouIds );
6230
6231   return newGroupIDs;
6232 }
6233
6234 //================================================================================
6235 /*!
6236  * \brief Return list of group of nodes close to each other within theTolerance
6237  *        Search among theNodes or in the whole mesh if theNodes is empty using
6238  *        an Octree algorithm
6239  */
6240 //================================================================================
6241
6242 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6243                                             const double         theTolerance,
6244                                             TListOfListOfNodes & theGroupsOfNodes)
6245 {
6246   myLastCreatedElems.Clear();
6247   myLastCreatedNodes.Clear();
6248
6249   if ( theNodes.empty() )
6250   { // get all nodes in the mesh
6251     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6252     while ( nIt->more() )
6253       theNodes.insert( theNodes.end(),nIt->next());
6254   }
6255
6256   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6257 }
6258
6259 //=======================================================================
6260 //function : SimplifyFace
6261 //purpose  :
6262 //=======================================================================
6263
6264 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *>& faceNodes,
6265                                     vector<const SMDS_MeshNode *>&       poly_nodes,
6266                                     vector<int>&                         quantities) const
6267 {
6268   int nbNodes = faceNodes.size();
6269
6270   if (nbNodes < 3)
6271     return 0;
6272
6273   set<const SMDS_MeshNode*> nodeSet;
6274
6275   // get simple seq of nodes
6276   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6277   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6278   int iSimple = 0, nbUnique = 0;
6279
6280   simpleNodes[iSimple++] = faceNodes[0];
6281   nbUnique++;
6282   for (int iCur = 1; iCur < nbNodes; iCur++) {
6283     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6284       simpleNodes[iSimple++] = faceNodes[iCur];
6285       if (nodeSet.insert( faceNodes[iCur] ).second)
6286         nbUnique++;
6287     }
6288   }
6289   int nbSimple = iSimple;
6290   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6291     nbSimple--;
6292     iSimple--;
6293   }
6294
6295   if (nbUnique < 3)
6296     return 0;
6297
6298   // separate loops
6299   int nbNew = 0;
6300   bool foundLoop = (nbSimple > nbUnique);
6301   while (foundLoop) {
6302     foundLoop = false;
6303     set<const SMDS_MeshNode*> loopSet;
6304     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6305       const SMDS_MeshNode* n = simpleNodes[iSimple];
6306       if (!loopSet.insert( n ).second) {
6307         foundLoop = true;
6308
6309         // separate loop
6310         int iC = 0, curLast = iSimple;
6311         for (; iC < curLast; iC++) {
6312           if (simpleNodes[iC] == n) break;
6313         }
6314         int loopLen = curLast - iC;
6315         if (loopLen > 2) {
6316           // create sub-element
6317           nbNew++;
6318           quantities.push_back(loopLen);
6319           for (; iC < curLast; iC++) {
6320             poly_nodes.push_back(simpleNodes[iC]);
6321           }
6322         }
6323         // shift the rest nodes (place from the first loop position)
6324         for (iC = curLast + 1; iC < nbSimple; iC++) {
6325           simpleNodes[iC - loopLen] = simpleNodes[iC];
6326         }
6327         nbSimple -= loopLen;
6328         iSimple -= loopLen;
6329       }
6330     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6331   } // while (foundLoop)
6332
6333   if (iSimple > 2) {
6334     nbNew++;
6335     quantities.push_back(iSimple);
6336     for (int i = 0; i < iSimple; i++)
6337       poly_nodes.push_back(simpleNodes[i]);
6338   }
6339
6340   return nbNew;
6341 }
6342
6343 //=======================================================================
6344 //function : MergeNodes
6345 //purpose  : In each group, the cdr of nodes are substituted by the first one
6346 //           in all elements.
6347 //=======================================================================
6348
6349 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6350 {
6351   MESSAGE("MergeNodes");
6352   myLastCreatedElems.Clear();
6353   myLastCreatedNodes.Clear();
6354
6355   SMESHDS_Mesh* aMesh = GetMeshDS();
6356
6357   TNodeNodeMap nodeNodeMap; // node to replace - new node
6358   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6359   list< int > rmElemIds, rmNodeIds;
6360
6361   // Fill nodeNodeMap and elems
6362
6363   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6364   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6365     list<const SMDS_MeshNode*>& nodes = *grIt;
6366     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6367     const SMDS_MeshNode* nToKeep = *nIt;
6368     //MESSAGE("node to keep " << nToKeep->GetID());
6369     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6370       const SMDS_MeshNode* nToRemove = *nIt;
6371       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6372       if ( nToRemove != nToKeep ) {
6373         //MESSAGE("  node to remove " << nToRemove->GetID());
6374         rmNodeIds.push_back( nToRemove->GetID() );
6375         AddToSameGroups( nToKeep, nToRemove, aMesh );
6376         // set _alwaysComputed to a sub-mesh of VERTEX to enable mesh computing
6377         // after MergeNodes() w/o creating node in place of merged ones.
6378         const SMDS_PositionPtr& pos = nToRemove->GetPosition();
6379         if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX )
6380           if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() ))
6381             sm->SetIsAlwaysComputed( true );
6382       }
6383
6384       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6385       while ( invElemIt->more() ) {
6386         const SMDS_MeshElement* elem = invElemIt->next();
6387         elems.insert(elem);
6388       }
6389     }
6390   }
6391   // Change element nodes or remove an element
6392
6393   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6394   for ( ; eIt != elems.end(); eIt++ ) {
6395     const SMDS_MeshElement* elem = *eIt;
6396     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
6397     int nbNodes = elem->NbNodes();
6398     int aShapeId = FindShape( elem );
6399
6400     set<const SMDS_MeshNode*> nodeSet;
6401     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6402     int iUnique = 0, iCur = 0, nbRepl = 0;
6403     vector<int> iRepl( nbNodes );
6404
6405     // get new seq of nodes
6406     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6407     while ( itN->more() ) {
6408       const SMDS_MeshNode* n =
6409         static_cast<const SMDS_MeshNode*>( itN->next() );
6410
6411       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6412       if ( nnIt != nodeNodeMap.end() ) { // n sticks
6413         n = (*nnIt).second;
6414         // BUG 0020185: begin
6415         {
6416           bool stopRecur = false;
6417           set<const SMDS_MeshNode*> nodesRecur;
6418           nodesRecur.insert(n);
6419           while (!stopRecur) {
6420             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6421             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6422               n = (*nnIt_i).second;
6423               if (!nodesRecur.insert(n).second) {
6424                 // error: recursive dependancy
6425                 stopRecur = true;
6426               }
6427             }
6428             else
6429               stopRecur = true;
6430           }
6431         }
6432         // BUG 0020185: end
6433       }
6434       curNodes[ iCur ] = n;
6435       bool isUnique = nodeSet.insert( n ).second;
6436       if ( isUnique )
6437         uniqueNodes[ iUnique++ ] = n;
6438       else
6439         iRepl[ nbRepl++ ] = iCur;
6440       iCur++;
6441     }
6442
6443     // Analyse element topology after replacement
6444
6445     bool isOk = true;
6446     int nbUniqueNodes = nodeSet.size();
6447     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
6448     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6449       // Polygons and Polyhedral volumes
6450       if (elem->IsPoly()) {
6451
6452         if (elem->GetType() == SMDSAbs_Face) {
6453           // Polygon
6454           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6455           int inode = 0;
6456           for (; inode < nbNodes; inode++) {
6457             face_nodes[inode] = curNodes[inode];
6458           }
6459
6460           vector<const SMDS_MeshNode *> polygons_nodes;
6461           vector<int> quantities;
6462           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6463           if (nbNew > 0) {
6464             inode = 0;
6465             for (int iface = 0; iface < nbNew; iface++) {
6466               int nbNodes = quantities[iface];
6467               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6468               for (int ii = 0; ii < nbNodes; ii++, inode++) {
6469                 poly_nodes[ii] = polygons_nodes[inode];
6470               }
6471               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6472               myLastCreatedElems.Append(newElem);
6473               if (aShapeId)
6474                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6475             }
6476
6477             MESSAGE("ChangeElementNodes MergeNodes Polygon");
6478             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6479             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
6480             int quid =0;
6481             if (nbNew > 0) quid = nbNew - 1;
6482             vector<int> newquant(quantities.begin()+quid, quantities.end());
6483             const SMDS_MeshElement* newElem = 0;
6484             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
6485             myLastCreatedElems.Append(newElem);
6486             if ( aShapeId && newElem )
6487               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6488             rmElemIds.push_back(elem->GetID());
6489           }
6490           else {
6491             rmElemIds.push_back(elem->GetID());
6492           }
6493
6494         }
6495         else if (elem->GetType() == SMDSAbs_Volume) {
6496           // Polyhedral volume
6497           if (nbUniqueNodes < 4) {
6498             rmElemIds.push_back(elem->GetID());
6499           }
6500           else {
6501             // each face has to be analyzed in order to check volume validity
6502             const SMDS_VtkVolume* aPolyedre =
6503               dynamic_cast<const SMDS_VtkVolume*>( elem );
6504             if (aPolyedre) {
6505               int nbFaces = aPolyedre->NbFaces();
6506
6507               vector<const SMDS_MeshNode *> poly_nodes;
6508               vector<int> quantities;
6509
6510               for (int iface = 1; iface <= nbFaces; iface++) {
6511                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6512                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
6513
6514                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
6515                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
6516                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
6517                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
6518                     faceNode = (*nnIt).second;
6519                   }
6520                   faceNodes[inode - 1] = faceNode;
6521                 }
6522
6523                 SimplifyFace(faceNodes, poly_nodes, quantities);
6524               }
6525
6526               if (quantities.size() > 3) {
6527                 // to be done: remove coincident faces
6528               }
6529
6530               if (quantities.size() > 3)
6531                 {
6532                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
6533                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6534                   const SMDS_MeshElement* newElem = 0;
6535                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
6536                   myLastCreatedElems.Append(newElem);
6537                   if ( aShapeId && newElem )
6538                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
6539                   rmElemIds.push_back(elem->GetID());
6540                 }
6541             }
6542             else {
6543               rmElemIds.push_back(elem->GetID());
6544             }
6545           }
6546         }
6547         else {
6548         }
6549
6550         continue;
6551       } // poly element
6552
6553       // Regular elements
6554       // TODO not all the possible cases are solved. Find something more generic?
6555       switch ( nbNodes ) {
6556       case 2: ///////////////////////////////////// EDGE
6557         isOk = false; break;
6558       case 3: ///////////////////////////////////// TRIANGLE
6559         isOk = false; break;
6560       case 4:
6561         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
6562           isOk = false;
6563         else { //////////////////////////////////// QUADRANGLE
6564           if ( nbUniqueNodes < 3 )
6565             isOk = false;
6566           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
6567             isOk = false; // opposite nodes stick
6568           //MESSAGE("isOk " << isOk);
6569         }
6570         break;
6571       case 6: ///////////////////////////////////// PENTAHEDRON
6572         if ( nbUniqueNodes == 4 ) {
6573           // ---------------------------------> tetrahedron
6574           if (nbRepl == 3 &&
6575               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
6576             // all top nodes stick: reverse a bottom
6577             uniqueNodes[ 0 ] = curNodes [ 1 ];
6578             uniqueNodes[ 1 ] = curNodes [ 0 ];
6579           }
6580           else if (nbRepl == 3 &&
6581                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
6582             // all bottom nodes stick: set a top before
6583             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
6584             uniqueNodes[ 0 ] = curNodes [ 3 ];
6585             uniqueNodes[ 1 ] = curNodes [ 4 ];
6586             uniqueNodes[ 2 ] = curNodes [ 5 ];
6587           }
6588           else if (nbRepl == 4 &&
6589                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
6590             // a lateral face turns into a line: reverse a bottom
6591             uniqueNodes[ 0 ] = curNodes [ 1 ];
6592             uniqueNodes[ 1 ] = curNodes [ 0 ];
6593           }
6594           else
6595             isOk = false;
6596         }
6597         else if ( nbUniqueNodes == 5 ) {
6598           // PENTAHEDRON --------------------> 2 tetrahedrons
6599           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6600             // a bottom node sticks with a linked top one
6601             // 1.
6602             SMDS_MeshElement* newElem =
6603               aMesh->AddVolume(curNodes[ 3 ],
6604                                curNodes[ 4 ],
6605                                curNodes[ 5 ],
6606                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6607             myLastCreatedElems.Append(newElem);
6608             if ( aShapeId )
6609               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6610             // 2. : reverse a bottom
6611             uniqueNodes[ 0 ] = curNodes [ 1 ];
6612             uniqueNodes[ 1 ] = curNodes [ 0 ];
6613             nbUniqueNodes = 4;
6614           }
6615           else
6616             isOk = false;
6617         }
6618         else
6619           isOk = false;
6620         break;
6621       case 8: {
6622         if(elem->IsQuadratic()) { // Quadratic quadrangle
6623           //   1    5    2
6624           //    +---+---+
6625           //    |       |
6626           //    |       |
6627           //   4+       +6
6628           //    |       |
6629           //    |       |
6630           //    +---+---+
6631           //   0    7    3
6632           isOk = false;
6633           if(nbRepl==2) {
6634             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
6635           }
6636           if(nbRepl==3) {
6637             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
6638             nbUniqueNodes = 6;
6639             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6640               uniqueNodes[0] = curNodes[0];
6641               uniqueNodes[1] = curNodes[2];
6642               uniqueNodes[2] = curNodes[3];
6643               uniqueNodes[3] = curNodes[5];
6644               uniqueNodes[4] = curNodes[6];
6645               uniqueNodes[5] = curNodes[7];
6646               isOk = true;
6647             }
6648             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6649               uniqueNodes[0] = curNodes[0];
6650               uniqueNodes[1] = curNodes[1];
6651               uniqueNodes[2] = curNodes[2];
6652               uniqueNodes[3] = curNodes[4];
6653               uniqueNodes[4] = curNodes[5];
6654               uniqueNodes[5] = curNodes[6];
6655               isOk = true;
6656             }
6657             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6658               uniqueNodes[0] = curNodes[1];
6659               uniqueNodes[1] = curNodes[2];
6660               uniqueNodes[2] = curNodes[3];
6661               uniqueNodes[3] = curNodes[5];
6662               uniqueNodes[4] = curNodes[6];
6663               uniqueNodes[5] = curNodes[0];
6664               isOk = true;
6665             }
6666             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
6667               uniqueNodes[0] = curNodes[0];
6668               uniqueNodes[1] = curNodes[1];
6669               uniqueNodes[2] = curNodes[3];
6670               uniqueNodes[3] = curNodes[4];
6671               uniqueNodes[4] = curNodes[6];
6672               uniqueNodes[5] = curNodes[7];
6673               isOk = true;
6674             }
6675             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
6676               uniqueNodes[0] = curNodes[0];
6677               uniqueNodes[1] = curNodes[2];
6678               uniqueNodes[2] = curNodes[3];
6679               uniqueNodes[3] = curNodes[1];
6680               uniqueNodes[4] = curNodes[6];
6681               uniqueNodes[5] = curNodes[7];
6682               isOk = true;
6683             }
6684             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
6685               uniqueNodes[0] = curNodes[0];
6686               uniqueNodes[1] = curNodes[1];
6687               uniqueNodes[2] = curNodes[2];
6688               uniqueNodes[3] = curNodes[4];
6689               uniqueNodes[4] = curNodes[5];
6690               uniqueNodes[5] = curNodes[7];
6691               isOk = true;
6692             }
6693             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
6694               uniqueNodes[0] = curNodes[0];
6695               uniqueNodes[1] = curNodes[1];
6696               uniqueNodes[2] = curNodes[3];
6697               uniqueNodes[3] = curNodes[4];
6698               uniqueNodes[4] = curNodes[2];
6699               uniqueNodes[5] = curNodes[7];
6700               isOk = true;
6701             }
6702             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
6703               uniqueNodes[0] = curNodes[0];
6704               uniqueNodes[1] = curNodes[1];
6705               uniqueNodes[2] = curNodes[2];
6706               uniqueNodes[3] = curNodes[4];
6707               uniqueNodes[4] = curNodes[5];
6708               uniqueNodes[5] = curNodes[3];
6709               isOk = true;
6710             }
6711           }
6712           if(nbRepl==4) {
6713             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
6714           }
6715           if(nbRepl==5) {
6716             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
6717           }
6718           break;
6719         }
6720         //////////////////////////////////// HEXAHEDRON
6721         isOk = false;
6722         SMDS_VolumeTool hexa (elem);
6723         hexa.SetExternalNormal();
6724         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
6725           //////////////////////// HEX ---> 1 tetrahedron
6726           for ( int iFace = 0; iFace < 6; iFace++ ) {
6727             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6728             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6729                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6730                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6731               // one face turns into a point ...
6732               int iOppFace = hexa.GetOppFaceIndex( iFace );
6733               ind = hexa.GetFaceNodesIndices( iOppFace );
6734               int nbStick = 0;
6735               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
6736                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6737                   nbStick++;
6738               }
6739               if ( nbStick == 1 ) {
6740                 // ... and the opposite one - into a triangle.
6741                 // set a top node
6742                 ind = hexa.GetFaceNodesIndices( iFace );
6743                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
6744                 isOk = true;
6745               }
6746               break;
6747             }
6748           }
6749         }
6750         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
6751           //////////////////////// HEX ---> 1 prism
6752           int nbTria = 0, iTria[3];
6753           const int *ind; // indices of face nodes
6754           // look for triangular faces
6755           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
6756             ind = hexa.GetFaceNodesIndices( iFace );
6757             TIDSortedNodeSet faceNodes;
6758             for ( iCur = 0; iCur < 4; iCur++ )
6759               faceNodes.insert( curNodes[ind[iCur]] );
6760             if ( faceNodes.size() == 3 )
6761               iTria[ nbTria++ ] = iFace;
6762           }
6763           // check if triangles are opposite
6764           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
6765           {
6766             isOk = true;
6767             // set nodes of the bottom triangle
6768             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
6769             vector<int> indB;
6770             for ( iCur = 0; iCur < 4; iCur++ )
6771               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
6772                 indB.push_back( ind[iCur] );
6773             if ( !hexa.IsForward() )
6774               std::swap( indB[0], indB[2] );
6775             for ( iCur = 0; iCur < 3; iCur++ )
6776               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
6777             // set nodes of the top triangle
6778             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
6779             for ( iCur = 0; iCur < 3; ++iCur )
6780               for ( int j = 0; j < 4; ++j )
6781                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
6782                 {
6783                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
6784                   break;
6785                 }
6786           }
6787           break;
6788         }
6789         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
6790           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
6791           for ( int iFace = 0; iFace < 6; iFace++ ) {
6792             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6793             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6794                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6795                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6796               // one face turns into a point ...
6797               int iOppFace = hexa.GetOppFaceIndex( iFace );
6798               ind = hexa.GetFaceNodesIndices( iOppFace );
6799               int nbStick = 0;
6800               iUnique = 2;  // reverse a tetrahedron 1 bottom
6801               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
6802                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6803                   nbStick++;
6804                 else if ( iUnique >= 0 )
6805                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6806               }
6807               if ( nbStick == 0 ) {
6808                 // ... and the opposite one is a quadrangle
6809                 // set a top node
6810                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
6811                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
6812                 nbUniqueNodes = 4;
6813                 // tetrahedron 2
6814                 SMDS_MeshElement* newElem =
6815                   aMesh->AddVolume(curNodes[ind[ 0 ]],
6816                                    curNodes[ind[ 3 ]],
6817                                    curNodes[ind[ 2 ]],
6818                                    curNodes[indTop[ 0 ]]);
6819                 myLastCreatedElems.Append(newElem);
6820                 if ( aShapeId )
6821                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
6822                 isOk = true;
6823               }
6824               break;
6825             }
6826           }
6827         }
6828         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
6829           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
6830           // find indices of quad and tri faces
6831           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
6832           for ( iFace = 0; iFace < 6; iFace++ ) {
6833             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6834             nodeSet.clear();
6835             for ( iCur = 0; iCur < 4; iCur++ )
6836               nodeSet.insert( curNodes[ind[ iCur ]] );
6837             nbUniqueNodes = nodeSet.size();
6838             if ( nbUniqueNodes == 3 )
6839               iTriFace[ nbTri++ ] = iFace;
6840             else if ( nbUniqueNodes == 4 )
6841               iQuadFace[ nbQuad++ ] = iFace;
6842           }
6843           if (nbQuad == 2 && nbTri == 4 &&
6844               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
6845             // 2 opposite quadrangles stuck with a diagonal;
6846             // sample groups of merged indices: (0-4)(2-6)
6847             // --------------------------------------------> 2 tetrahedrons
6848             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
6849             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
6850             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
6851             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
6852                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
6853               // stuck with 0-2 diagonal
6854               i0  = ind1[ 3 ];
6855               i1d = ind1[ 0 ];
6856               i2  = ind1[ 1 ];
6857               i3d = ind1[ 2 ];
6858               i0t = ind2[ 1 ];
6859               i2t = ind2[ 3 ];
6860             }
6861             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
6862                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
6863               // stuck with 1-3 diagonal
6864               i0  = ind1[ 0 ];
6865               i1d = ind1[ 1 ];
6866               i2  = ind1[ 2 ];
6867               i3d = ind1[ 3 ];
6868               i0t = ind2[ 0 ];
6869               i2t = ind2[ 1 ];
6870             }
6871             else {
6872               ASSERT(0);
6873             }
6874             // tetrahedron 1
6875             uniqueNodes[ 0 ] = curNodes [ i0 ];
6876             uniqueNodes[ 1 ] = curNodes [ i1d ];
6877             uniqueNodes[ 2 ] = curNodes [ i3d ];
6878             uniqueNodes[ 3 ] = curNodes [ i0t ];
6879             nbUniqueNodes = 4;
6880             // tetrahedron 2
6881             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
6882                                                          curNodes[ i2 ],
6883                                                          curNodes[ i3d ],
6884                                                          curNodes[ i2t ]);
6885             myLastCreatedElems.Append(newElem);
6886             if ( aShapeId )
6887               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6888             isOk = true;
6889           }
6890           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
6891                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
6892             // --------------------------------------------> prism
6893             // find 2 opposite triangles
6894             nbUniqueNodes = 6;
6895             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
6896               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
6897                 // find indices of kept and replaced nodes
6898                 // and fill unique nodes of 2 opposite triangles
6899                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
6900                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
6901                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
6902                 // fill unique nodes
6903                 iUnique = 0;
6904                 isOk = true;
6905                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
6906                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
6907                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
6908                   if ( n == nInit ) {
6909                     // iCur of a linked node of the opposite face (make normals co-directed):
6910                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
6911                     // check that correspondent corners of triangles are linked
6912                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
6913                       isOk = false;
6914                     else {
6915                       uniqueNodes[ iUnique ] = n;
6916                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
6917                       iUnique++;
6918                     }
6919                   }
6920                 }
6921                 break;
6922               }
6923             }
6924           }
6925         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
6926         else
6927         {
6928           MESSAGE("MergeNodes() removes hexahedron "<< elem);
6929         }
6930         break;
6931       } // HEXAHEDRON
6932
6933       default:
6934         isOk = false;
6935       } // switch ( nbNodes )
6936
6937     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
6938
6939     if ( isOk ) { // the elem remains valid after sticking nodes
6940       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
6941       {
6942         // Change nodes of polyedre
6943         const SMDS_VtkVolume* aPolyedre =
6944           dynamic_cast<const SMDS_VtkVolume*>( elem );
6945         if (aPolyedre) {
6946           int nbFaces = aPolyedre->NbFaces();
6947
6948           vector<const SMDS_MeshNode *> poly_nodes;
6949           vector<int> quantities (nbFaces);
6950
6951           for (int iface = 1; iface <= nbFaces; iface++) {
6952             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6953             quantities[iface - 1] = nbFaceNodes;
6954
6955             for (inode = 1; inode <= nbFaceNodes; inode++) {
6956               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
6957
6958               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
6959               if (nnIt != nodeNodeMap.end()) { // curNode sticks
6960                 curNode = (*nnIt).second;
6961               }
6962               poly_nodes.push_back(curNode);
6963             }
6964           }
6965           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
6966         }
6967       }
6968       else // replace non-polyhedron elements
6969       {
6970         const SMDSAbs_ElementType etyp = elem->GetType();
6971         const int elemId               = elem->GetID();
6972         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
6973         uniqueNodes.resize(nbUniqueNodes);
6974
6975         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
6976
6977         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
6978         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
6979         if ( sm && newElem )
6980           sm->AddElement( newElem );
6981         if ( elem != newElem )
6982           ReplaceElemInGroups( elem, newElem, aMesh );
6983       }
6984     }
6985     else {
6986       // Remove invalid regular element or invalid polygon
6987       rmElemIds.push_back( elem->GetID() );
6988     }
6989
6990   } // loop on elements
6991
6992   // Remove bad elements, then equal nodes (order important)
6993
6994   Remove( rmElemIds, false );
6995   Remove( rmNodeIds, true );
6996
6997 }
6998
6999
7000 // ========================================================
7001 // class   : SortableElement
7002 // purpose : allow sorting elements basing on their nodes
7003 // ========================================================
7004 class SortableElement : public set <const SMDS_MeshElement*>
7005 {
7006 public:
7007
7008   SortableElement( const SMDS_MeshElement* theElem )
7009   {
7010     myElem = theElem;
7011     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7012     while ( nodeIt->more() )
7013       this->insert( nodeIt->next() );
7014   }
7015
7016   const SMDS_MeshElement* Get() const
7017   { return myElem; }
7018
7019   void Set(const SMDS_MeshElement* e) const
7020   { myElem = e; }
7021
7022
7023 private:
7024   mutable const SMDS_MeshElement* myElem;
7025 };
7026
7027 //=======================================================================
7028 //function : FindEqualElements
7029 //purpose  : Return list of group of elements built on the same nodes.
7030 //           Search among theElements or in the whole mesh if theElements is empty
7031 //=======================================================================
7032
7033 void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet &        theElements,
7034                                          TListOfListOfElementsID & theGroupsOfElementsID)
7035 {
7036   myLastCreatedElems.Clear();
7037   myLastCreatedNodes.Clear();
7038
7039   typedef map< SortableElement, int > TMapOfNodeSet;
7040   typedef list<int> TGroupOfElems;
7041
7042   if ( theElements.empty() )
7043   { // get all elements in the mesh
7044     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7045     while ( eIt->more() )
7046       theElements.insert( theElements.end(), eIt->next());
7047   }
7048
7049   vector< TGroupOfElems > arrayOfGroups;
7050   TGroupOfElems groupOfElems;
7051   TMapOfNodeSet mapOfNodeSet;
7052
7053   TIDSortedElemSet::iterator elemIt = theElements.begin();
7054   for ( int i = 0, j=0; elemIt != theElements.end(); ++elemIt, ++j ) {
7055     const SMDS_MeshElement* curElem = *elemIt;
7056     SortableElement SE(curElem);
7057     int ind = -1;
7058     // check uniqueness
7059     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7060     if( !(pp.second) ) {
7061       TMapOfNodeSet::iterator& itSE = pp.first;
7062       ind = (*itSE).second;
7063       arrayOfGroups[ind].push_back(curElem->GetID());
7064     }
7065     else {
7066       groupOfElems.clear();
7067       groupOfElems.push_back(curElem->GetID());
7068       arrayOfGroups.push_back(groupOfElems);
7069       i++;
7070     }
7071   }
7072
7073   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7074   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7075     groupOfElems = *groupIt;
7076     if ( groupOfElems.size() > 1 ) {
7077       groupOfElems.sort();
7078       theGroupsOfElementsID.push_back(groupOfElems);
7079     }
7080   }
7081 }
7082
7083 //=======================================================================
7084 //function : MergeElements
7085 //purpose  : In each given group, substitute all elements by the first one.
7086 //=======================================================================
7087
7088 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7089 {
7090   myLastCreatedElems.Clear();
7091   myLastCreatedNodes.Clear();
7092
7093   typedef list<int> TListOfIDs;
7094   TListOfIDs rmElemIds; // IDs of elems to remove
7095
7096   SMESHDS_Mesh* aMesh = GetMeshDS();
7097
7098   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7099   while ( groupsIt != theGroupsOfElementsID.end() ) {
7100     TListOfIDs& aGroupOfElemID = *groupsIt;
7101     aGroupOfElemID.sort();
7102     int elemIDToKeep = aGroupOfElemID.front();
7103     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7104     aGroupOfElemID.pop_front();
7105     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7106     while ( idIt != aGroupOfElemID.end() ) {
7107       int elemIDToRemove = *idIt;
7108       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7109       // add the kept element in groups of removed one (PAL15188)
7110       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7111       rmElemIds.push_back( elemIDToRemove );
7112       ++idIt;
7113     }
7114     ++groupsIt;
7115   }
7116
7117   Remove( rmElemIds, false );
7118 }
7119
7120 //=======================================================================
7121 //function : MergeEqualElements
7122 //purpose  : Remove all but one of elements built on the same nodes.
7123 //=======================================================================
7124
7125 void SMESH_MeshEditor::MergeEqualElements()
7126 {
7127   TIDSortedElemSet aMeshElements; /* empty input ==
7128                                      to merge equal elements in the whole mesh */
7129   TListOfListOfElementsID aGroupsOfElementsID;
7130   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7131   MergeElements(aGroupsOfElementsID);
7132 }
7133
7134 //=======================================================================
7135 //function : findAdjacentFace
7136 //purpose  :
7137 //=======================================================================
7138
7139 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7140                                                 const SMDS_MeshNode* n2,
7141                                                 const SMDS_MeshElement* elem)
7142 {
7143   TIDSortedElemSet elemSet, avoidSet;
7144   if ( elem )
7145     avoidSet.insert ( elem );
7146   return SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet );
7147 }
7148
7149 //=======================================================================
7150 //function : FindFreeBorder
7151 //purpose  :
7152 //=======================================================================
7153
7154 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7155
7156 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7157                                        const SMDS_MeshNode*             theSecondNode,
7158                                        const SMDS_MeshNode*             theLastNode,
7159                                        list< const SMDS_MeshNode* > &   theNodes,
7160                                        list< const SMDS_MeshElement* >& theFaces)
7161 {
7162   if ( !theFirstNode || !theSecondNode )
7163     return false;
7164   // find border face between theFirstNode and theSecondNode
7165   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7166   if ( !curElem )
7167     return false;
7168
7169   theFaces.push_back( curElem );
7170   theNodes.push_back( theFirstNode );
7171   theNodes.push_back( theSecondNode );
7172
7173   //vector<const SMDS_MeshNode*> nodes;
7174   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7175   TIDSortedElemSet foundElems;
7176   bool needTheLast = ( theLastNode != 0 );
7177
7178   while ( nStart != theLastNode ) {
7179     if ( nStart == theFirstNode )
7180       return !needTheLast;
7181
7182     // find all free border faces sharing form nStart
7183
7184     list< const SMDS_MeshElement* > curElemList;
7185     list< const SMDS_MeshNode* > nStartList;
7186     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7187     while ( invElemIt->more() ) {
7188       const SMDS_MeshElement* e = invElemIt->next();
7189       if ( e == curElem || foundElems.insert( e ).second ) {
7190         // get nodes
7191         int iNode = 0, nbNodes = e->NbNodes();
7192         //const SMDS_MeshNode* nodes[nbNodes+1];
7193         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7194
7195         if(e->IsQuadratic()) {
7196           const SMDS_VtkFace* F =
7197             dynamic_cast<const SMDS_VtkFace*>(e);
7198           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7199           // use special nodes iterator
7200           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7201           while( anIter->more() ) {
7202             nodes[ iNode++ ] = cast2Node(anIter->next());
7203           }
7204         }
7205         else {
7206           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7207           while ( nIt->more() )
7208             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7209         }
7210         nodes[ iNode ] = nodes[ 0 ];
7211         // check 2 links
7212         for ( iNode = 0; iNode < nbNodes; iNode++ )
7213           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7214                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7215               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7216           {
7217             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7218             curElemList.push_back( e );
7219           }
7220       }
7221     }
7222     // analyse the found
7223
7224     int nbNewBorders = curElemList.size();
7225     if ( nbNewBorders == 0 ) {
7226       // no free border furthermore
7227       return !needTheLast;
7228     }
7229     else if ( nbNewBorders == 1 ) {
7230       // one more element found
7231       nIgnore = nStart;
7232       nStart = nStartList.front();
7233       curElem = curElemList.front();
7234       theFaces.push_back( curElem );
7235       theNodes.push_back( nStart );
7236     }
7237     else {
7238       // several continuations found
7239       list< const SMDS_MeshElement* >::iterator curElemIt;
7240       list< const SMDS_MeshNode* >::iterator nStartIt;
7241       // check if one of them reached the last node
7242       if ( needTheLast ) {
7243         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7244              curElemIt!= curElemList.end();
7245              curElemIt++, nStartIt++ )
7246           if ( *nStartIt == theLastNode ) {
7247             theFaces.push_back( *curElemIt );
7248             theNodes.push_back( *nStartIt );
7249             return true;
7250           }
7251       }
7252       // find the best free border by the continuations
7253       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7254       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7255       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7256            curElemIt!= curElemList.end();
7257            curElemIt++, nStartIt++ )
7258       {
7259         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7260         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7261         // find one more free border
7262         if ( ! SMESH_MeshEditor::FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7263           cNL->clear();
7264           cFL->clear();
7265         }
7266         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7267           // choice: clear a worse one
7268           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7269           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7270           contNodes[ iWorse ].clear();
7271           contFaces[ iWorse ].clear();
7272         }
7273       }
7274       if ( contNodes[0].empty() && contNodes[1].empty() )
7275         return false;
7276
7277       // append the best free border
7278       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7279       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7280       theNodes.pop_back(); // remove nIgnore
7281       theNodes.pop_back(); // remove nStart
7282       theFaces.pop_back(); // remove curElem
7283       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7284       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7285       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7286       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7287       return true;
7288
7289     } // several continuations found
7290   } // while ( nStart != theLastNode )
7291
7292   return true;
7293 }
7294
7295 //=======================================================================
7296 //function : CheckFreeBorderNodes
7297 //purpose  : Return true if the tree nodes are on a free border
7298 //=======================================================================
7299
7300 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7301                                             const SMDS_MeshNode* theNode2,
7302                                             const SMDS_MeshNode* theNode3)
7303 {
7304   list< const SMDS_MeshNode* > nodes;
7305   list< const SMDS_MeshElement* > faces;
7306   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7307 }
7308
7309 //=======================================================================
7310 //function : SewFreeBorder
7311 //purpose  :
7312 //=======================================================================
7313
7314 SMESH_MeshEditor::Sew_Error
7315 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7316                                  const SMDS_MeshNode* theBordSecondNode,
7317                                  const SMDS_MeshNode* theBordLastNode,
7318                                  const SMDS_MeshNode* theSideFirstNode,
7319                                  const SMDS_MeshNode* theSideSecondNode,
7320                                  const SMDS_MeshNode* theSideThirdNode,
7321                                  const bool           theSideIsFreeBorder,
7322                                  const bool           toCreatePolygons,
7323                                  const bool           toCreatePolyedrs)
7324 {
7325   myLastCreatedElems.Clear();
7326   myLastCreatedNodes.Clear();
7327
7328   MESSAGE("::SewFreeBorder()");
7329   Sew_Error aResult = SEW_OK;
7330
7331   // ====================================
7332   //    find side nodes and elements
7333   // ====================================
7334
7335   list< const SMDS_MeshNode* > nSide[ 2 ];
7336   list< const SMDS_MeshElement* > eSide[ 2 ];
7337   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7338   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7339
7340   // Free border 1
7341   // --------------
7342   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7343                       nSide[0], eSide[0])) {
7344     MESSAGE(" Free Border 1 not found " );
7345     aResult = SEW_BORDER1_NOT_FOUND;
7346   }
7347   if (theSideIsFreeBorder) {
7348     // Free border 2
7349     // --------------
7350     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7351                         nSide[1], eSide[1])) {
7352       MESSAGE(" Free Border 2 not found " );
7353       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7354     }
7355   }
7356   if ( aResult != SEW_OK )
7357     return aResult;
7358
7359   if (!theSideIsFreeBorder) {
7360     // Side 2
7361     // --------------
7362
7363     // -------------------------------------------------------------------------
7364     // Algo:
7365     // 1. If nodes to merge are not coincident, move nodes of the free border
7366     //    from the coord sys defined by the direction from the first to last
7367     //    nodes of the border to the correspondent sys of the side 2
7368     // 2. On the side 2, find the links most co-directed with the correspondent
7369     //    links of the free border
7370     // -------------------------------------------------------------------------
7371
7372     // 1. Since sewing may break if there are volumes to split on the side 2,
7373     //    we wont move nodes but just compute new coordinates for them
7374     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7375     TNodeXYZMap nBordXYZ;
7376     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7377     list< const SMDS_MeshNode* >::iterator nBordIt;
7378
7379     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7380     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7381     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7382     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7383     double tol2 = 1.e-8;
7384     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7385     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7386       // Need node movement.
7387
7388       // find X and Z axes to create trsf
7389       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7390       gp_Vec X = Zs ^ Zb;
7391       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7392         // Zb || Zs
7393         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7394
7395       // coord systems
7396       gp_Ax3 toBordAx( Pb1, Zb, X );
7397       gp_Ax3 fromSideAx( Ps1, Zs, X );
7398       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7399       // set trsf
7400       gp_Trsf toBordSys, fromSide2Sys;
7401       toBordSys.SetTransformation( toBordAx );
7402       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7403       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7404
7405       // move
7406       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7407         const SMDS_MeshNode* n = *nBordIt;
7408         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7409         toBordSys.Transforms( xyz );
7410         fromSide2Sys.Transforms( xyz );
7411         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7412       }
7413     }
7414     else {
7415       // just insert nodes XYZ in the nBordXYZ map
7416       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7417         const SMDS_MeshNode* n = *nBordIt;
7418         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7419       }
7420     }
7421
7422     // 2. On the side 2, find the links most co-directed with the correspondent
7423     //    links of the free border
7424
7425     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7426     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7427     sideNodes.push_back( theSideFirstNode );
7428
7429     bool hasVolumes = false;
7430     LinkID_Gen aLinkID_Gen( GetMeshDS() );
7431     set<long> foundSideLinkIDs, checkedLinkIDs;
7432     SMDS_VolumeTool volume;
7433     //const SMDS_MeshNode* faceNodes[ 4 ];
7434
7435     const SMDS_MeshNode*    sideNode;
7436     const SMDS_MeshElement* sideElem;
7437     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7438     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7439     nBordIt = bordNodes.begin();
7440     nBordIt++;
7441     // border node position and border link direction to compare with
7442     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7443     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7444     // choose next side node by link direction or by closeness to
7445     // the current border node:
7446     bool searchByDir = ( *nBordIt != theBordLastNode );
7447     do {
7448       // find the next node on the Side 2
7449       sideNode = 0;
7450       double maxDot = -DBL_MAX, minDist = DBL_MAX;
7451       long linkID;
7452       checkedLinkIDs.clear();
7453       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7454
7455       // loop on inverse elements of current node (prevSideNode) on the Side 2
7456       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7457       while ( invElemIt->more() )
7458       {
7459         const SMDS_MeshElement* elem = invElemIt->next();
7460         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7461         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7462         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7463         bool isVolume = volume.Set( elem );
7464         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7465         if ( isVolume ) // --volume
7466           hasVolumes = true;
7467         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7468           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7469           if(elem->IsQuadratic()) {
7470             const SMDS_VtkFace* F =
7471               dynamic_cast<const SMDS_VtkFace*>(elem);
7472             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7473             // use special nodes iterator
7474             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7475             while( anIter->more() ) {
7476               nodes[ iNode ] = cast2Node(anIter->next());
7477               if ( nodes[ iNode++ ] == prevSideNode )
7478                 iPrevNode = iNode - 1;
7479             }
7480           }
7481           else {
7482             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7483             while ( nIt->more() ) {
7484               nodes[ iNode ] = cast2Node( nIt->next() );
7485               if ( nodes[ iNode++ ] == prevSideNode )
7486                 iPrevNode = iNode - 1;
7487             }
7488           }
7489           // there are 2 links to check
7490           nbNodes = 2;
7491         }
7492         else // --edge
7493           continue;
7494         // loop on links, to be precise, on the second node of links
7495         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7496           const SMDS_MeshNode* n = nodes[ iNode ];
7497           if ( isVolume ) {
7498             if ( !volume.IsLinked( n, prevSideNode ))
7499               continue;
7500           }
7501           else {
7502             if ( iNode ) // a node before prevSideNode
7503               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7504             else         // a node after prevSideNode
7505               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7506           }
7507           // check if this link was already used
7508           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7509           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7510           if (!isJustChecked &&
7511               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7512           {
7513             // test a link geometrically
7514             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
7515             bool linkIsBetter = false;
7516             double dot = 0.0, dist = 0.0;
7517             if ( searchByDir ) { // choose most co-directed link
7518               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
7519               linkIsBetter = ( dot > maxDot );
7520             }
7521             else { // choose link with the node closest to bordPos
7522               dist = ( nextXYZ - bordPos ).SquareModulus();
7523               linkIsBetter = ( dist < minDist );
7524             }
7525             if ( linkIsBetter ) {
7526               maxDot = dot;
7527               minDist = dist;
7528               linkID = iLink;
7529               sideNode = n;
7530               sideElem = elem;
7531             }
7532           }
7533         }
7534       } // loop on inverse elements of prevSideNode
7535
7536       if ( !sideNode ) {
7537         MESSAGE(" Cant find path by links of the Side 2 ");
7538         return SEW_BAD_SIDE_NODES;
7539       }
7540       sideNodes.push_back( sideNode );
7541       sideElems.push_back( sideElem );
7542       foundSideLinkIDs.insert ( linkID );
7543       prevSideNode = sideNode;
7544
7545       if ( *nBordIt == theBordLastNode )
7546         searchByDir = false;
7547       else {
7548         // find the next border link to compare with
7549         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
7550         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7551         // move to next border node if sideNode is before forward border node (bordPos)
7552         while ( *nBordIt != theBordLastNode && !searchByDir ) {
7553           prevBordNode = *nBordIt;
7554           nBordIt++;
7555           bordPos = nBordXYZ[ *nBordIt ];
7556           bordDir = bordPos - nBordXYZ[ prevBordNode ];
7557           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7558         }
7559       }
7560     }
7561     while ( sideNode != theSideSecondNode );
7562
7563     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
7564       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
7565       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
7566     }
7567   } // end nodes search on the side 2
7568
7569   // ============================
7570   // sew the border to the side 2
7571   // ============================
7572
7573   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
7574   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
7575
7576   TListOfListOfNodes nodeGroupsToMerge;
7577   if ( nbNodes[0] == nbNodes[1] ||
7578        ( theSideIsFreeBorder && !theSideThirdNode)) {
7579
7580     // all nodes are to be merged
7581
7582     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
7583          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
7584          nIt[0]++, nIt[1]++ )
7585     {
7586       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7587       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
7588       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
7589     }
7590   }
7591   else {
7592
7593     // insert new nodes into the border and the side to get equal nb of segments
7594
7595     // get normalized parameters of nodes on the borders
7596     //double param[ 2 ][ maxNbNodes ];
7597     double* param[ 2 ];
7598     param[0] = new double [ maxNbNodes ];
7599     param[1] = new double [ maxNbNodes ];
7600     int iNode, iBord;
7601     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7602       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7603       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
7604       const SMDS_MeshNode* nPrev = *nIt;
7605       double bordLength = 0;
7606       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7607         const SMDS_MeshNode* nCur = *nIt;
7608         gp_XYZ segment (nCur->X() - nPrev->X(),
7609                         nCur->Y() - nPrev->Y(),
7610                         nCur->Z() - nPrev->Z());
7611         double segmentLen = segment.Modulus();
7612         bordLength += segmentLen;
7613         param[ iBord ][ iNode ] = bordLength;
7614         nPrev = nCur;
7615       }
7616       // normalize within [0,1]
7617       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7618         param[ iBord ][ iNode ] /= bordLength;
7619       }
7620     }
7621
7622     // loop on border segments
7623     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7624     int i[ 2 ] = { 0, 0 };
7625     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7626     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7627
7628     TElemOfNodeListMap insertMap;
7629     TElemOfNodeListMap::iterator insertMapIt;
7630     // insertMap is
7631     // key:   elem to insert nodes into
7632     // value: 2 nodes to insert between + nodes to be inserted
7633     do {
7634       bool next[ 2 ] = { false, false };
7635
7636       // find min adjacent segment length after sewing
7637       double nextParam = 10., prevParam = 0;
7638       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7639         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7640           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7641         if ( i[ iBord ] > 0 )
7642           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7643       }
7644       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7645       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7646       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7647
7648       // choose to insert or to merge nodes
7649       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7650       if ( Abs( du ) <= minSegLen * 0.2 ) {
7651         // merge
7652         // ------
7653         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7654         const SMDS_MeshNode* n0 = *nIt[0];
7655         const SMDS_MeshNode* n1 = *nIt[1];
7656         nodeGroupsToMerge.back().push_back( n1 );
7657         nodeGroupsToMerge.back().push_back( n0 );
7658         // position of node of the border changes due to merge
7659         param[ 0 ][ i[0] ] += du;
7660         // move n1 for the sake of elem shape evaluation during insertion.
7661         // n1 will be removed by MergeNodes() anyway
7662         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
7663         next[0] = next[1] = true;
7664       }
7665       else {
7666         // insert
7667         // ------
7668         int intoBord = ( du < 0 ) ? 0 : 1;
7669         const SMDS_MeshElement* elem = *eIt[ intoBord ];
7670         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
7671         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
7672         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
7673         if ( intoBord == 1 ) {
7674           // move node of the border to be on a link of elem of the side
7675           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
7676           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
7677           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
7678           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
7679           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
7680         }
7681         insertMapIt = insertMap.find( elem );
7682         bool notFound = ( insertMapIt == insertMap.end() );
7683         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
7684         if ( otherLink ) {
7685           // insert into another link of the same element:
7686           // 1. perform insertion into the other link of the elem
7687           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7688           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
7689           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
7690           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
7691           // 2. perform insertion into the link of adjacent faces
7692           while (true) {
7693             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
7694             if ( adjElem )
7695               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
7696             else
7697               break;
7698           }
7699           if (toCreatePolyedrs) {
7700             // perform insertion into the links of adjacent volumes
7701             UpdateVolumes(n12, n22, nodeList);
7702           }
7703           // 3. find an element appeared on n1 and n2 after the insertion
7704           insertMap.erase( elem );
7705           elem = findAdjacentFace( n1, n2, 0 );
7706         }
7707         if ( notFound || otherLink ) {
7708           // add element and nodes of the side into the insertMap
7709           insertMapIt = insertMap.insert
7710             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
7711           (*insertMapIt).second.push_back( n1 );
7712           (*insertMapIt).second.push_back( n2 );
7713         }
7714         // add node to be inserted into elem
7715         (*insertMapIt).second.push_back( nIns );
7716         next[ 1 - intoBord ] = true;
7717       }
7718
7719       // go to the next segment
7720       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7721         if ( next[ iBord ] ) {
7722           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
7723             eIt[ iBord ]++;
7724           nPrev[ iBord ] = *nIt[ iBord ];
7725           nIt[ iBord ]++; i[ iBord ]++;
7726         }
7727       }
7728     }
7729     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
7730
7731     // perform insertion of nodes into elements
7732
7733     for (insertMapIt = insertMap.begin();
7734          insertMapIt != insertMap.end();
7735          insertMapIt++ )
7736     {
7737       const SMDS_MeshElement* elem = (*insertMapIt).first;
7738       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7739       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
7740       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
7741
7742       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
7743
7744       if ( !theSideIsFreeBorder ) {
7745         // look for and insert nodes into the faces adjacent to elem
7746         while (true) {
7747           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
7748           if ( adjElem )
7749             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
7750           else
7751             break;
7752         }
7753       }
7754       if (toCreatePolyedrs) {
7755         // perform insertion into the links of adjacent volumes
7756         UpdateVolumes(n1, n2, nodeList);
7757       }
7758     }
7759
7760     delete param[0];
7761     delete param[1];
7762   } // end: insert new nodes
7763
7764   MergeNodes ( nodeGroupsToMerge );
7765
7766   return aResult;
7767 }
7768
7769 //=======================================================================
7770 //function : InsertNodesIntoLink
7771 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
7772 //           and theBetweenNode2 and split theElement
7773 //=======================================================================
7774
7775 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
7776                                            const SMDS_MeshNode*        theBetweenNode1,
7777                                            const SMDS_MeshNode*        theBetweenNode2,
7778                                            list<const SMDS_MeshNode*>& theNodesToInsert,
7779                                            const bool                  toCreatePoly)
7780 {
7781   if ( theFace->GetType() != SMDSAbs_Face ) return;
7782
7783   // find indices of 2 link nodes and of the rest nodes
7784   int iNode = 0, il1, il2, i3, i4;
7785   il1 = il2 = i3 = i4 = -1;
7786   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
7787   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
7788
7789   if(theFace->IsQuadratic()) {
7790     const SMDS_VtkFace* F =
7791       dynamic_cast<const SMDS_VtkFace*>(theFace);
7792     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7793     // use special nodes iterator
7794     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7795     while( anIter->more() ) {
7796       const SMDS_MeshNode* n = cast2Node(anIter->next());
7797       if ( n == theBetweenNode1 )
7798         il1 = iNode;
7799       else if ( n == theBetweenNode2 )
7800         il2 = iNode;
7801       else if ( i3 < 0 )
7802         i3 = iNode;
7803       else
7804         i4 = iNode;
7805       nodes[ iNode++ ] = n;
7806     }
7807   }
7808   else {
7809     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7810     while ( nodeIt->more() ) {
7811       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7812       if ( n == theBetweenNode1 )
7813         il1 = iNode;
7814       else if ( n == theBetweenNode2 )
7815         il2 = iNode;
7816       else if ( i3 < 0 )
7817         i3 = iNode;
7818       else
7819         i4 = iNode;
7820       nodes[ iNode++ ] = n;
7821     }
7822   }
7823   if ( il1 < 0 || il2 < 0 || i3 < 0 )
7824     return ;
7825
7826   // arrange link nodes to go one after another regarding the face orientation
7827   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
7828   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
7829   if ( reverse ) {
7830     iNode = il1;
7831     il1 = il2;
7832     il2 = iNode;
7833     aNodesToInsert.reverse();
7834   }
7835   // check that not link nodes of a quadrangles are in good order
7836   int nbFaceNodes = theFace->NbNodes();
7837   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
7838     iNode = i3;
7839     i3 = i4;
7840     i4 = iNode;
7841   }
7842
7843   if (toCreatePoly || theFace->IsPoly()) {
7844
7845     iNode = 0;
7846     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
7847
7848     // add nodes of face up to first node of link
7849     bool isFLN = false;
7850
7851     if(theFace->IsQuadratic()) {
7852       const SMDS_VtkFace* F =
7853         dynamic_cast<const SMDS_VtkFace*>(theFace);
7854       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7855       // use special nodes iterator
7856       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7857       while( anIter->more()  && !isFLN ) {
7858         const SMDS_MeshNode* n = cast2Node(anIter->next());
7859         poly_nodes[iNode++] = n;
7860         if (n == nodes[il1]) {
7861           isFLN = true;
7862         }
7863       }
7864       // add nodes to insert
7865       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7866       for (; nIt != aNodesToInsert.end(); nIt++) {
7867         poly_nodes[iNode++] = *nIt;
7868       }
7869       // add nodes of face starting from last node of link
7870       while ( anIter->more() ) {
7871         poly_nodes[iNode++] = cast2Node(anIter->next());
7872       }
7873     }
7874     else {
7875       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7876       while ( nodeIt->more() && !isFLN ) {
7877         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7878         poly_nodes[iNode++] = n;
7879         if (n == nodes[il1]) {
7880           isFLN = true;
7881         }
7882       }
7883       // add nodes to insert
7884       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7885       for (; nIt != aNodesToInsert.end(); nIt++) {
7886         poly_nodes[iNode++] = *nIt;
7887       }
7888       // add nodes of face starting from last node of link
7889       while ( nodeIt->more() ) {
7890         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7891         poly_nodes[iNode++] = n;
7892       }
7893     }
7894
7895     // edit or replace the face
7896     SMESHDS_Mesh *aMesh = GetMeshDS();
7897
7898     if (theFace->IsPoly()) {
7899       aMesh->ChangePolygonNodes(theFace, poly_nodes);
7900     }
7901     else {
7902       int aShapeId = FindShape( theFace );
7903
7904       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7905       myLastCreatedElems.Append(newElem);
7906       if ( aShapeId && newElem )
7907         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7908
7909       aMesh->RemoveElement(theFace);
7910     }
7911     return;
7912   }
7913
7914   SMESHDS_Mesh *aMesh = GetMeshDS();
7915   if( !theFace->IsQuadratic() ) {
7916
7917     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
7918     int nbLinkNodes = 2 + aNodesToInsert.size();
7919     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
7920     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
7921     linkNodes[ 0 ] = nodes[ il1 ];
7922     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
7923     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7924     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7925       linkNodes[ iNode++ ] = *nIt;
7926     }
7927     // decide how to split a quadrangle: compare possible variants
7928     // and choose which of splits to be a quadrangle
7929     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
7930     if ( nbFaceNodes == 3 ) {
7931       iBestQuad = nbSplits;
7932       i4 = i3;
7933     }
7934     else if ( nbFaceNodes == 4 ) {
7935       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
7936       double aBestRate = DBL_MAX;
7937       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
7938         i1 = 0; i2 = 1;
7939         double aBadRate = 0;
7940         // evaluate elements quality
7941         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
7942           if ( iSplit == iQuad ) {
7943             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
7944                                    linkNodes[ i2++ ],
7945                                    nodes[ i3 ],
7946                                    nodes[ i4 ]);
7947             aBadRate += getBadRate( &quad, aCrit );
7948           }
7949           else {
7950             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
7951                                    linkNodes[ i2++ ],
7952                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
7953             aBadRate += getBadRate( &tria, aCrit );
7954           }
7955         }
7956         // choice
7957         if ( aBadRate < aBestRate ) {
7958           iBestQuad = iQuad;
7959           aBestRate = aBadRate;
7960         }
7961       }
7962     }
7963
7964     // create new elements
7965     int aShapeId = FindShape( theFace );
7966
7967     i1 = 0; i2 = 1;
7968     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
7969       SMDS_MeshElement* newElem = 0;
7970       if ( iSplit == iBestQuad )
7971         newElem = aMesh->AddFace (linkNodes[ i1++ ],
7972                                   linkNodes[ i2++ ],
7973                                   nodes[ i3 ],
7974                                   nodes[ i4 ]);
7975       else
7976         newElem = aMesh->AddFace (linkNodes[ i1++ ],
7977                                   linkNodes[ i2++ ],
7978                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
7979       myLastCreatedElems.Append(newElem);
7980       if ( aShapeId && newElem )
7981         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7982     }
7983
7984     // change nodes of theFace
7985     const SMDS_MeshNode* newNodes[ 4 ];
7986     newNodes[ 0 ] = linkNodes[ i1 ];
7987     newNodes[ 1 ] = linkNodes[ i2 ];
7988     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
7989     newNodes[ 3 ] = nodes[ i4 ];
7990     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
7991     const SMDS_MeshElement* newElem = 0;
7992     if (iSplit == iBestQuad)
7993       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
7994     else
7995       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
7996     myLastCreatedElems.Append(newElem);
7997     if ( aShapeId && newElem )
7998       aMesh->SetMeshElementOnShape( newElem, aShapeId );
7999 } // end if(!theFace->IsQuadratic())
8000   else { // theFace is quadratic
8001     // we have to split theFace on simple triangles and one simple quadrangle
8002     int tmp = il1/2;
8003     int nbshift = tmp*2;
8004     // shift nodes in nodes[] by nbshift
8005     int i,j;
8006     for(i=0; i<nbshift; i++) {
8007       const SMDS_MeshNode* n = nodes[0];
8008       for(j=0; j<nbFaceNodes-1; j++) {
8009         nodes[j] = nodes[j+1];
8010       }
8011       nodes[nbFaceNodes-1] = n;
8012     }
8013     il1 = il1 - nbshift;
8014     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8015     //   n0      n1     n2    n0      n1     n2
8016     //     +-----+-----+        +-----+-----+
8017     //      \         /         |           |
8018     //       \       /          |           |
8019     //      n5+     +n3       n7+           +n3
8020     //         \   /            |           |
8021     //          \ /             |           |
8022     //           +              +-----+-----+
8023     //           n4           n6      n5     n4
8024
8025     // create new elements
8026     int aShapeId = FindShape( theFace );
8027
8028     int n1,n2,n3;
8029     if(nbFaceNodes==6) { // quadratic triangle
8030       SMDS_MeshElement* newElem =
8031         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8032       myLastCreatedElems.Append(newElem);
8033       if ( aShapeId && newElem )
8034         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8035       if(theFace->IsMediumNode(nodes[il1])) {
8036         // create quadrangle
8037         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8038         myLastCreatedElems.Append(newElem);
8039         if ( aShapeId && newElem )
8040           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8041         n1 = 1;
8042         n2 = 2;
8043         n3 = 3;
8044       }
8045       else {
8046         // create quadrangle
8047         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8048         myLastCreatedElems.Append(newElem);
8049         if ( aShapeId && newElem )
8050           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8051         n1 = 0;
8052         n2 = 1;
8053         n3 = 5;
8054       }
8055     }
8056     else { // nbFaceNodes==8 - quadratic quadrangle
8057       SMDS_MeshElement* newElem =
8058         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8059       myLastCreatedElems.Append(newElem);
8060       if ( aShapeId && newElem )
8061         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8062       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8063       myLastCreatedElems.Append(newElem);
8064       if ( aShapeId && newElem )
8065         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8066       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8067       myLastCreatedElems.Append(newElem);
8068       if ( aShapeId && newElem )
8069         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8070       if(theFace->IsMediumNode(nodes[il1])) {
8071         // create quadrangle
8072         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8073         myLastCreatedElems.Append(newElem);
8074         if ( aShapeId && newElem )
8075           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8076         n1 = 1;
8077         n2 = 2;
8078         n3 = 3;
8079       }
8080       else {
8081         // create quadrangle
8082         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8083         myLastCreatedElems.Append(newElem);
8084         if ( aShapeId && newElem )
8085           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8086         n1 = 0;
8087         n2 = 1;
8088         n3 = 7;
8089       }
8090     }
8091     // create needed triangles using n1,n2,n3 and inserted nodes
8092     int nbn = 2 + aNodesToInsert.size();
8093     //const SMDS_MeshNode* aNodes[nbn];
8094     vector<const SMDS_MeshNode*> aNodes(nbn);
8095     aNodes[0] = nodes[n1];
8096     aNodes[nbn-1] = nodes[n2];
8097     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8098     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8099       aNodes[iNode++] = *nIt;
8100     }
8101     for(i=1; i<nbn; i++) {
8102       SMDS_MeshElement* newElem =
8103         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8104       myLastCreatedElems.Append(newElem);
8105       if ( aShapeId && newElem )
8106         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8107     }
8108   }
8109   // remove old face
8110   aMesh->RemoveElement(theFace);
8111 }
8112
8113 //=======================================================================
8114 //function : UpdateVolumes
8115 //purpose  :
8116 //=======================================================================
8117 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8118                                       const SMDS_MeshNode*        theBetweenNode2,
8119                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8120 {
8121   myLastCreatedElems.Clear();
8122   myLastCreatedNodes.Clear();
8123
8124   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8125   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8126     const SMDS_MeshElement* elem = invElemIt->next();
8127
8128     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8129     SMDS_VolumeTool aVolume (elem);
8130     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8131       continue;
8132
8133     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8134     int iface, nbFaces = aVolume.NbFaces();
8135     vector<const SMDS_MeshNode *> poly_nodes;
8136     vector<int> quantities (nbFaces);
8137
8138     for (iface = 0; iface < nbFaces; iface++) {
8139       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8140       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8141       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8142
8143       for (int inode = 0; inode < nbFaceNodes; inode++) {
8144         poly_nodes.push_back(faceNodes[inode]);
8145
8146         if (nbInserted == 0) {
8147           if (faceNodes[inode] == theBetweenNode1) {
8148             if (faceNodes[inode + 1] == theBetweenNode2) {
8149               nbInserted = theNodesToInsert.size();
8150
8151               // add nodes to insert
8152               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8153               for (; nIt != theNodesToInsert.end(); nIt++) {
8154                 poly_nodes.push_back(*nIt);
8155               }
8156             }
8157           }
8158           else if (faceNodes[inode] == theBetweenNode2) {
8159             if (faceNodes[inode + 1] == theBetweenNode1) {
8160               nbInserted = theNodesToInsert.size();
8161
8162               // add nodes to insert in reversed order
8163               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8164               nIt--;
8165               for (; nIt != theNodesToInsert.begin(); nIt--) {
8166                 poly_nodes.push_back(*nIt);
8167               }
8168               poly_nodes.push_back(*nIt);
8169             }
8170           }
8171           else {
8172           }
8173         }
8174       }
8175       quantities[iface] = nbFaceNodes + nbInserted;
8176     }
8177
8178     // Replace or update the volume
8179     SMESHDS_Mesh *aMesh = GetMeshDS();
8180
8181     if (elem->IsPoly()) {
8182       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8183
8184     }
8185     else {
8186       int aShapeId = FindShape( elem );
8187
8188       SMDS_MeshElement* newElem =
8189         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8190       myLastCreatedElems.Append(newElem);
8191       if (aShapeId && newElem)
8192         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8193
8194       aMesh->RemoveElement(elem);
8195     }
8196   }
8197 }
8198
8199 namespace
8200 {
8201   //================================================================================
8202   /*!
8203    * \brief Transform any volume into data of SMDSEntity_Polyhedra
8204    */
8205   //================================================================================
8206
8207   void volumeToPolyhedron( const SMDS_MeshElement*         elem,
8208                            vector<const SMDS_MeshNode *> & nodes,
8209                            vector<int> &                   nbNodeInFaces )
8210   {
8211     nodes.clear();
8212     nbNodeInFaces.clear();
8213     SMDS_VolumeTool vTool ( elem );
8214     for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
8215     {
8216       const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
8217       nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
8218       nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
8219     }
8220   }
8221 }
8222
8223 //=======================================================================
8224 /*!
8225  * \brief Convert elements contained in a submesh to quadratic
8226  * \return int - nb of checked elements
8227  */
8228 //=======================================================================
8229
8230 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8231                                              SMESH_MesherHelper& theHelper,
8232                                              const bool          theForce3d)
8233 {
8234   int nbElem = 0;
8235   if( !theSm ) return nbElem;
8236
8237   vector<int> nbNodeInFaces;
8238   vector<const SMDS_MeshNode *> nodes;
8239   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8240   while(ElemItr->more())
8241   {
8242     nbElem++;
8243     const SMDS_MeshElement* elem = ElemItr->next();
8244     if( !elem ) continue;
8245
8246     // analyse a necessity of conversion
8247     const SMDSAbs_ElementType aType = elem->GetType();
8248     if ( aType < SMDSAbs_Edge || aType > SMDSAbs_Volume )
8249       continue;
8250     const SMDSAbs_EntityType aGeomType = elem->GetEntityType();
8251     bool hasCentralNodes = false;
8252     if ( elem->IsQuadratic() )
8253     {
8254       bool alreadyOK;
8255       switch ( aGeomType ) {
8256       case SMDSEntity_Quad_Triangle:
8257       case SMDSEntity_Quad_Quadrangle:
8258       case SMDSEntity_Quad_Hexa:
8259         alreadyOK = !theHelper.GetIsBiQuadratic(); break;
8260
8261       case SMDSEntity_BiQuad_Triangle:
8262       case SMDSEntity_BiQuad_Quadrangle:
8263       case SMDSEntity_TriQuad_Hexa:
8264         alreadyOK = theHelper.GetIsBiQuadratic();
8265         hasCentralNodes = true;
8266         break;
8267       default:
8268         alreadyOK = true;
8269       }
8270       // take into account already present modium nodes
8271       switch ( aType ) {
8272       case SMDSAbs_Volume:
8273         theHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( elem )); break;
8274       case SMDSAbs_Face:
8275         theHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem )); break;
8276       case SMDSAbs_Edge:
8277         theHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( elem )); break;
8278       default:;
8279       }
8280       if ( alreadyOK )
8281         continue;
8282     }
8283     // get elem data needed to re-create it
8284     //
8285     const int id      = elem->GetID();
8286     const int nbNodes = elem->NbCornerNodes();
8287     nodes.assign(elem->begin_nodes(), elem->end_nodes());
8288     if ( aGeomType == SMDSEntity_Polyhedra )
8289       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
8290     else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
8291       volumeToPolyhedron( elem, nodes, nbNodeInFaces );
8292
8293     // remove a linear element
8294     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
8295
8296     // remove central nodes of biquadratic elements (biquad->quad convertion)
8297     if ( hasCentralNodes )
8298       for ( size_t i = nbNodes * 2; i < nodes.size(); ++i )
8299         if ( nodes[i]->NbInverseElements() == 0 )
8300           GetMeshDS()->RemoveFreeNode( nodes[i], theSm, /*fromGroups=*/true );
8301
8302     const SMDS_MeshElement* NewElem = 0;
8303
8304     switch( aType )
8305     {
8306     case SMDSAbs_Edge :
8307       {
8308         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8309         break;
8310       }
8311     case SMDSAbs_Face :
8312       {
8313         switch(nbNodes)
8314         {
8315         case 3:
8316           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8317           break;
8318         case 4:
8319           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8320           break;
8321         default:
8322           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
8323         }
8324         break;
8325       }
8326     case SMDSAbs_Volume :
8327       {
8328         switch( aGeomType )
8329         {
8330         case SMDSEntity_Tetra:
8331           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8332           break;
8333         case SMDSEntity_Pyramid:
8334           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
8335           break;
8336         case SMDSEntity_Penta:
8337           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
8338           break;
8339         case SMDSEntity_Hexa:
8340         case SMDSEntity_Quad_Hexa:
8341         case SMDSEntity_TriQuad_Hexa:
8342           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8343                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8344           break;
8345         case SMDSEntity_Hexagonal_Prism:
8346         default:
8347           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8348         }
8349         break;
8350       }
8351     default :
8352       continue;
8353     }
8354     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8355     if( NewElem && NewElem->getshapeId() < 1 )
8356       theSm->AddElement( NewElem );
8357   }
8358   return nbElem;
8359 }
8360 //=======================================================================
8361 //function : ConvertToQuadratic
8362 //purpose  :
8363 //=======================================================================
8364
8365 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad)
8366 {
8367   SMESHDS_Mesh* meshDS = GetMeshDS();
8368
8369   SMESH_MesherHelper aHelper(*myMesh);
8370
8371   aHelper.SetIsQuadratic( true );
8372   aHelper.SetIsBiQuadratic( theToBiQuad );
8373   aHelper.SetElementsOnShape(true);
8374
8375   // convert elements assigned to sub-meshes
8376   int nbCheckedElems = 0;
8377   if ( myMesh->HasShapeToMesh() )
8378   {
8379     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8380     {
8381       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8382       while ( smIt->more() ) {
8383         SMESH_subMesh* sm = smIt->next();
8384         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8385           aHelper.SetSubShape( sm->GetSubShape() );
8386           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8387         }
8388       }
8389     }
8390   }
8391
8392   // convert elements NOT assigned to sub-meshes
8393   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8394   if ( nbCheckedElems < totalNbElems ) // not all elements are in sub-meshes
8395   {
8396     aHelper.SetElementsOnShape(false);
8397     SMESHDS_SubMesh *smDS = 0;
8398
8399     // convert edges
8400     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8401     while( aEdgeItr->more() )
8402     {
8403       const SMDS_MeshEdge* edge = aEdgeItr->next();
8404       if ( !edge->IsQuadratic() )
8405       {
8406         int                  id = edge->GetID();
8407         const SMDS_MeshNode* n1 = edge->GetNode(0);
8408         const SMDS_MeshNode* n2 = edge->GetNode(1);
8409
8410         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
8411
8412         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8413         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8414       }
8415       else
8416       {
8417         aHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( edge ));
8418       }
8419     }
8420
8421     // convert faces
8422     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8423     while( aFaceItr->more() )
8424     {
8425       const SMDS_MeshFace* face = aFaceItr->next();
8426       if ( !face ) continue;
8427       
8428       const SMDSAbs_EntityType type = face->GetEntityType();
8429       bool alreadyOK;
8430       switch( type )
8431       {
8432       case SMDSEntity_Quad_Triangle:
8433       case SMDSEntity_Quad_Quadrangle:
8434         alreadyOK = !theToBiQuad;
8435         aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
8436         break;
8437       case SMDSEntity_BiQuad_Triangle:
8438       case SMDSEntity_BiQuad_Quadrangle:
8439         alreadyOK = theToBiQuad;
8440         aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
8441         break;
8442       default: alreadyOK = false;
8443       }
8444       if ( alreadyOK )
8445         continue;
8446
8447       const int id = face->GetID();
8448       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
8449
8450       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
8451
8452       SMDS_MeshFace * NewFace = 0;
8453       switch( type )
8454       {
8455       case SMDSEntity_Triangle:
8456       case SMDSEntity_Quad_Triangle:
8457       case SMDSEntity_BiQuad_Triangle:
8458         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8459         if ( nodes.size() == 7 && nodes[6]->NbInverseElements() == 0 ) // rm a central node
8460           GetMeshDS()->RemoveFreeNode( nodes[6], /*sm=*/0, /*fromGroups=*/true );
8461         break;
8462
8463       case SMDSEntity_Quadrangle:
8464       case SMDSEntity_Quad_Quadrangle:
8465       case SMDSEntity_BiQuad_Quadrangle:
8466         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8467         if ( nodes.size() == 9 && nodes[8]->NbInverseElements() == 0 ) // rm a central node
8468           GetMeshDS()->RemoveFreeNode( nodes[8], /*sm=*/0, /*fromGroups=*/true );
8469         break;
8470
8471       default:;
8472         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
8473       }
8474       ReplaceElemInGroups( face, NewFace, GetMeshDS());
8475     }
8476
8477     // convert volumes
8478     vector<int> nbNodeInFaces;
8479     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8480     while(aVolumeItr->more())
8481     {
8482       const SMDS_MeshVolume* volume = aVolumeItr->next();
8483       if ( !volume ) continue;
8484
8485       const SMDSAbs_EntityType type = volume->GetEntityType();
8486       if (( theToBiQuad  && type == SMDSEntity_TriQuad_Hexa ) ||
8487           ( !theToBiQuad && type == SMDSEntity_Quad_Hexa ))
8488       {
8489         aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume ));
8490         continue;
8491       }
8492       const int id = volume->GetID();
8493       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
8494       if ( type == SMDSEntity_Polyhedra )
8495         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
8496       else if ( type == SMDSEntity_Hexagonal_Prism )
8497         volumeToPolyhedron( volume, nodes, nbNodeInFaces );
8498
8499       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
8500
8501       SMDS_MeshVolume * NewVolume = 0;
8502       switch ( type )
8503       {
8504       case SMDSEntity_Tetra:
8505         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
8506         break;
8507       case SMDSEntity_Hexa:
8508       case SMDSEntity_Quad_Hexa:
8509       case SMDSEntity_TriQuad_Hexa:
8510         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8511                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8512         for ( size_t i = 20; i < nodes.size(); ++i ) // rm central nodes
8513           if ( nodes[i]->NbInverseElements() == 0 )
8514             GetMeshDS()->RemoveFreeNode( nodes[i], /*sm=*/0, /*fromGroups=*/true );
8515         break;
8516       case SMDSEntity_Pyramid:
8517         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8518                                       nodes[3], nodes[4], id, theForce3d);
8519         break;
8520       case SMDSEntity_Penta:
8521         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8522                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
8523         break;
8524       case SMDSEntity_Hexagonal_Prism:
8525       default:
8526         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8527       }
8528       ReplaceElemInGroups(volume, NewVolume, meshDS);
8529     }
8530   }
8531
8532   if ( !theForce3d )
8533   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8534     // aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8535     // aHelper.FixQuadraticElements(myError);
8536     SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
8537   }
8538 }
8539
8540 //================================================================================
8541 /*!
8542  * \brief Makes given elements quadratic
8543  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
8544  *  \param theElements - elements to make quadratic
8545  */
8546 //================================================================================
8547
8548 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
8549                                           TIDSortedElemSet& theElements,
8550                                           const bool        theToBiQuad)
8551 {
8552   if ( theElements.empty() ) return;
8553
8554   // we believe that all theElements are of the same type
8555   const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
8556
8557   // get all nodes shared by theElements
8558   TIDSortedNodeSet allNodes;
8559   TIDSortedElemSet::iterator eIt = theElements.begin();
8560   for ( ; eIt != theElements.end(); ++eIt )
8561     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
8562
8563   // complete theElements with elements of lower dim whose all nodes are in allNodes
8564
8565   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
8566   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
8567   TIDSortedNodeSet::iterator nIt = allNodes.begin();
8568   for ( ; nIt != allNodes.end(); ++nIt )
8569   {
8570     const SMDS_MeshNode* n = *nIt;
8571     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
8572     while ( invIt->more() )
8573     {
8574       const SMDS_MeshElement*      e = invIt->next();
8575       const SMDSAbs_ElementType type = e->GetType();
8576       if ( e->IsQuadratic() )
8577       {
8578         quadAdjacentElems[ type ].insert( e );
8579
8580         bool alreadyOK;
8581         switch ( e->GetEntityType() ) {
8582         case SMDSEntity_Quad_Triangle:
8583         case SMDSEntity_Quad_Quadrangle:
8584         case SMDSEntity_Quad_Hexa:         alreadyOK = !theToBiQuad; break;
8585         case SMDSEntity_BiQuad_Triangle:
8586         case SMDSEntity_BiQuad_Quadrangle:
8587         case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; break;
8588         default:                           alreadyOK = true;
8589         }
8590         if ( alreadyOK )
8591           continue;
8592       }
8593       if ( type >= elemType )
8594         continue; // same type or more complex linear element
8595
8596       if ( !checkedAdjacentElems[ type ].insert( e ).second )
8597         continue; // e is already checked
8598
8599       // check nodes
8600       bool allIn = true;
8601       SMDS_NodeIteratorPtr nodeIt = e->nodeIterator();
8602       while ( nodeIt->more() && allIn )
8603         allIn = allNodes.count( nodeIt->next() );
8604       if ( allIn )
8605         theElements.insert(e );
8606     }
8607   }
8608
8609   SMESH_MesherHelper helper(*myMesh);
8610   helper.SetIsQuadratic( true );
8611   helper.SetIsBiQuadratic( theToBiQuad );
8612
8613   // add links of quadratic adjacent elements to the helper
8614
8615   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
8616     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
8617           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
8618     {
8619       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
8620     }
8621   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
8622     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
8623           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
8624     {
8625       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
8626     }
8627   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
8628     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
8629           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
8630     {
8631       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
8632     }
8633
8634   // make quadratic (or bi-tri-quadratic) elements instead of linear ones
8635
8636   SMESHDS_Mesh*  meshDS = GetMeshDS();
8637   SMESHDS_SubMesh* smDS = 0;
8638   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
8639   {
8640     const SMDS_MeshElement* elem = *eIt;
8641
8642     bool alreadyOK;
8643     int nbCentralNodes = 0;
8644     switch ( elem->GetEntityType() ) {
8645       // linear convertible
8646     case SMDSEntity_Edge:
8647     case SMDSEntity_Triangle:
8648     case SMDSEntity_Quadrangle:
8649     case SMDSEntity_Tetra:
8650     case SMDSEntity_Pyramid:
8651     case SMDSEntity_Hexa:
8652     case SMDSEntity_Penta:             alreadyOK = false;       nbCentralNodes = 0; break;
8653       // quadratic that can become bi-quadratic
8654     case SMDSEntity_Quad_Triangle:
8655     case SMDSEntity_Quad_Quadrangle:
8656     case SMDSEntity_Quad_Hexa:         alreadyOK =!theToBiQuad; nbCentralNodes = 0; break;
8657       // bi-quadratic
8658     case SMDSEntity_BiQuad_Triangle:
8659     case SMDSEntity_BiQuad_Quadrangle: alreadyOK = theToBiQuad; nbCentralNodes = 1; break;
8660     case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; nbCentralNodes = 7; break;
8661       // the rest
8662     default:                           alreadyOK = true;
8663     }
8664     if ( alreadyOK ) continue;
8665
8666     const SMDSAbs_ElementType type = elem->GetType();
8667     const int                   id = elem->GetID();
8668     const int              nbNodes = elem->NbCornerNodes();
8669     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
8670
8671     helper.SetSubShape( elem->getshapeId() );
8672
8673     if ( !smDS || !smDS->Contains( elem ))
8674       smDS = meshDS->MeshElements( elem->getshapeId() );
8675     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
8676
8677     SMDS_MeshElement * newElem = 0;
8678     switch( nbNodes )
8679     {
8680     case 4: // cases for most frequently used element types go first (for optimization)
8681       if ( type == SMDSAbs_Volume )
8682         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8683       else
8684         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8685       break;
8686     case 8:
8687       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8688                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8689       break;
8690     case 3:
8691       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
8692       break;
8693     case 2:
8694       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8695       break;
8696     case 5:
8697       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8698                                  nodes[4], id, theForce3d);
8699       break;
8700     case 6:
8701       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8702                                  nodes[4], nodes[5], id, theForce3d);
8703       break;
8704     default:;
8705     }
8706     ReplaceElemInGroups( elem, newElem, meshDS);
8707     if( newElem && smDS )
8708       smDS->AddElement( newElem );
8709
8710      // remove central nodes
8711     for ( size_t i = nodes.size() - nbCentralNodes; i < nodes.size(); ++i )
8712       if ( nodes[i]->NbInverseElements() == 0 )
8713         meshDS->RemoveFreeNode( nodes[i], smDS, /*fromGroups=*/true );
8714
8715   } // loop on theElements
8716
8717   if ( !theForce3d )
8718   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8719     // helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8720     // helper.FixQuadraticElements( myError );
8721     SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
8722   }
8723 }
8724
8725 //=======================================================================
8726 /*!
8727  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8728  * \return int - nb of checked elements
8729  */
8730 //=======================================================================
8731
8732 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
8733                                      SMDS_ElemIteratorPtr theItr,
8734                                      const int            theShapeID)
8735 {
8736   int nbElem = 0;
8737   SMESHDS_Mesh* meshDS = GetMeshDS();
8738
8739   while( theItr->more() )
8740   {
8741     const SMDS_MeshElement* elem = theItr->next();
8742     nbElem++;
8743     if( elem && elem->IsQuadratic())
8744     {
8745       int id                    = elem->GetID();
8746       int nbCornerNodes         = elem->NbCornerNodes();
8747       SMDSAbs_ElementType aType = elem->GetType();
8748
8749       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
8750
8751       //remove a quadratic element
8752       if ( !theSm || !theSm->Contains( elem ))
8753         theSm = meshDS->MeshElements( elem->getshapeId() );
8754       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
8755
8756       // remove medium nodes
8757       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
8758         if ( nodes[i]->NbInverseElements() == 0 )
8759           meshDS->RemoveFreeNode( nodes[i], theSm );
8760
8761       // add a linear element
8762       nodes.resize( nbCornerNodes );
8763       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
8764       ReplaceElemInGroups(elem, newElem, meshDS);
8765       if( theSm && newElem )
8766         theSm->AddElement( newElem );
8767     }
8768   }
8769   return nbElem;
8770 }
8771
8772 //=======================================================================
8773 //function : ConvertFromQuadratic
8774 //purpose  :
8775 //=======================================================================
8776
8777 bool SMESH_MeshEditor::ConvertFromQuadratic()
8778 {
8779   int nbCheckedElems = 0;
8780   if ( myMesh->HasShapeToMesh() )
8781   {
8782     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8783     {
8784       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8785       while ( smIt->more() ) {
8786         SMESH_subMesh* sm = smIt->next();
8787         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8788           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8789       }
8790     }
8791   }
8792
8793   int totalNbElems =
8794     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8795   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8796   {
8797     SMESHDS_SubMesh *aSM = 0;
8798     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8799   }
8800
8801   return true;
8802 }
8803
8804 namespace
8805 {
8806   //================================================================================
8807   /*!
8808    * \brief Return true if all medium nodes of the element are in the node set
8809    */
8810   //================================================================================
8811
8812   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
8813   {
8814     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
8815       if ( !nodeSet.count( elem->GetNode(i) ))
8816         return false;
8817     return true;
8818   }
8819 }
8820
8821 //================================================================================
8822 /*!
8823  * \brief Makes given elements linear
8824  */
8825 //================================================================================
8826
8827 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
8828 {
8829   if ( theElements.empty() ) return;
8830
8831   // collect IDs of medium nodes of theElements; some of these nodes will be removed
8832   set<int> mediumNodeIDs;
8833   TIDSortedElemSet::iterator eIt = theElements.begin();
8834   for ( ; eIt != theElements.end(); ++eIt )
8835   {
8836     const SMDS_MeshElement* e = *eIt;
8837     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
8838       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
8839   }
8840
8841   // replace given elements by linear ones
8842   SMDS_ElemIteratorPtr elemIt = elemSetIterator( theElements );
8843   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
8844
8845   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
8846   // except those elements sharing medium nodes of quadratic element whose medium nodes
8847   // are not all in mediumNodeIDs
8848
8849   // get remaining medium nodes
8850   TIDSortedNodeSet mediumNodes;
8851   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
8852   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
8853     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
8854       mediumNodes.insert( mediumNodes.end(), n );
8855
8856   // find more quadratic elements to convert
8857   TIDSortedElemSet moreElemsToConvert;
8858   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
8859   for ( ; nIt != mediumNodes.end(); ++nIt )
8860   {
8861     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
8862     while ( invIt->more() )
8863     {
8864       const SMDS_MeshElement* e = invIt->next();
8865       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
8866       {
8867         // find a more complex element including e and
8868         // whose medium nodes are not in mediumNodes
8869         bool complexFound = false;
8870         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
8871         {
8872           SMDS_ElemIteratorPtr invIt2 =
8873             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
8874           while ( invIt2->more() )
8875           {
8876             const SMDS_MeshElement* eComplex = invIt2->next();
8877             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
8878             {
8879               int nbCommonNodes = SMESH_MeshAlgos::GetCommonNodes( e, eComplex ).size();
8880               if ( nbCommonNodes == e->NbNodes())
8881               {
8882                 complexFound = true;
8883                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
8884                 break;
8885               }
8886             }
8887           }
8888         }
8889         if ( !complexFound )
8890           moreElemsToConvert.insert( e );
8891       }
8892     }
8893   }
8894   elemIt = elemSetIterator( moreElemsToConvert );
8895   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
8896 }
8897
8898 //=======================================================================
8899 //function : SewSideElements
8900 //purpose  :
8901 //=======================================================================
8902
8903 SMESH_MeshEditor::Sew_Error
8904 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
8905                                    TIDSortedElemSet&    theSide2,
8906                                    const SMDS_MeshNode* theFirstNode1,
8907                                    const SMDS_MeshNode* theFirstNode2,
8908                                    const SMDS_MeshNode* theSecondNode1,
8909                                    const SMDS_MeshNode* theSecondNode2)
8910 {
8911   myLastCreatedElems.Clear();
8912   myLastCreatedNodes.Clear();
8913
8914   MESSAGE ("::::SewSideElements()");
8915   if ( theSide1.size() != theSide2.size() )
8916     return SEW_DIFF_NB_OF_ELEMENTS;
8917
8918   Sew_Error aResult = SEW_OK;
8919   // Algo:
8920   // 1. Build set of faces representing each side
8921   // 2. Find which nodes of the side 1 to merge with ones on the side 2
8922   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8923
8924   // =======================================================================
8925   // 1. Build set of faces representing each side:
8926   // =======================================================================
8927   // a. build set of nodes belonging to faces
8928   // b. complete set of faces: find missing faces whose nodes are in set of nodes
8929   // c. create temporary faces representing side of volumes if correspondent
8930   //    face does not exist
8931
8932   SMESHDS_Mesh* aMesh = GetMeshDS();
8933   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
8934   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
8935   TIDSortedElemSet             faceSet1, faceSet2;
8936   set<const SMDS_MeshElement*> volSet1,  volSet2;
8937   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
8938   TIDSortedElemSet             * faceSetPtr[] = { &faceSet1, &faceSet2 };
8939   set<const SMDS_MeshElement*> *  volSetPtr[] = { &volSet1,  &volSet2  };
8940   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
8941   TIDSortedElemSet             * elemSetPtr[] = { &theSide1, &theSide2 };
8942   int iSide, iFace, iNode;
8943
8944   list<const SMDS_MeshElement* > tempFaceList;
8945   for ( iSide = 0; iSide < 2; iSide++ ) {
8946     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
8947     TIDSortedElemSet             * elemSet = elemSetPtr[ iSide ];
8948     TIDSortedElemSet             * faceSet = faceSetPtr[ iSide ];
8949     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
8950     set<const SMDS_MeshElement*>::iterator vIt;
8951     TIDSortedElemSet::iterator eIt;
8952     set<const SMDS_MeshNode*>::iterator    nIt;
8953
8954     // check that given nodes belong to given elements
8955     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
8956     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
8957     int firstIndex = -1, secondIndex = -1;
8958     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8959       const SMDS_MeshElement* elem = *eIt;
8960       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
8961       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
8962       if ( firstIndex > -1 && secondIndex > -1 ) break;
8963     }
8964     if ( firstIndex < 0 || secondIndex < 0 ) {
8965       // we can simply return until temporary faces created
8966       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
8967     }
8968
8969     // -----------------------------------------------------------
8970     // 1a. Collect nodes of existing faces
8971     //     and build set of face nodes in order to detect missing
8972     //     faces corresponding to sides of volumes
8973     // -----------------------------------------------------------
8974
8975     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
8976
8977     // loop on the given element of a side
8978     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8979       //const SMDS_MeshElement* elem = *eIt;
8980       const SMDS_MeshElement* elem = *eIt;
8981       if ( elem->GetType() == SMDSAbs_Face ) {
8982         faceSet->insert( elem );
8983         set <const SMDS_MeshNode*> faceNodeSet;
8984         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
8985         while ( nodeIt->more() ) {
8986           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8987           nodeSet->insert( n );
8988           faceNodeSet.insert( n );
8989         }
8990         setOfFaceNodeSet.insert( faceNodeSet );
8991       }
8992       else if ( elem->GetType() == SMDSAbs_Volume )
8993         volSet->insert( elem );
8994     }
8995     // ------------------------------------------------------------------------------
8996     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
8997     // ------------------------------------------------------------------------------
8998
8999     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9000       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9001       while ( fIt->more() ) { // loop on faces sharing a node
9002         const SMDS_MeshElement* f = fIt->next();
9003         if ( faceSet->find( f ) == faceSet->end() ) {
9004           // check if all nodes are in nodeSet and
9005           // complete setOfFaceNodeSet if they are
9006           set <const SMDS_MeshNode*> faceNodeSet;
9007           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9008           bool allInSet = true;
9009           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9010             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9011             if ( nodeSet->find( n ) == nodeSet->end() )
9012               allInSet = false;
9013             else
9014               faceNodeSet.insert( n );
9015           }
9016           if ( allInSet ) {
9017             faceSet->insert( f );
9018             setOfFaceNodeSet.insert( faceNodeSet );
9019           }
9020         }
9021       }
9022     }
9023
9024     // -------------------------------------------------------------------------
9025     // 1c. Create temporary faces representing sides of volumes if correspondent
9026     //     face does not exist
9027     // -------------------------------------------------------------------------
9028
9029     if ( !volSet->empty() ) {
9030       //int nodeSetSize = nodeSet->size();
9031
9032       // loop on given volumes
9033       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9034         SMDS_VolumeTool vol (*vIt);
9035         // loop on volume faces: find free faces
9036         // --------------------------------------
9037         list<const SMDS_MeshElement* > freeFaceList;
9038         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9039           if ( !vol.IsFreeFace( iFace ))
9040             continue;
9041           // check if there is already a face with same nodes in a face set
9042           const SMDS_MeshElement* aFreeFace = 0;
9043           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9044           int nbNodes = vol.NbFaceNodes( iFace );
9045           set <const SMDS_MeshNode*> faceNodeSet;
9046           vol.GetFaceNodes( iFace, faceNodeSet );
9047           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9048           if ( isNewFace ) {
9049             // no such a face is given but it still can exist, check it
9050             vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
9051             aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
9052           }
9053           if ( !aFreeFace ) {
9054             // create a temporary face
9055             if ( nbNodes == 3 ) {
9056               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9057               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9058             }
9059             else if ( nbNodes == 4 ) {
9060               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9061               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9062             }
9063             else {
9064               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9065               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9066               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9067             }
9068             if ( aFreeFace )
9069               tempFaceList.push_back( aFreeFace );
9070           }
9071
9072           if ( aFreeFace )
9073             freeFaceList.push_back( aFreeFace );
9074
9075         } // loop on faces of a volume
9076
9077         // choose one of several free faces of a volume
9078         // --------------------------------------------
9079         if ( freeFaceList.size() > 1 ) {
9080           // choose a face having max nb of nodes shared by other elems of a side
9081           int maxNbNodes = -1;
9082           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9083           while ( fIt != freeFaceList.end() ) { // loop on free faces
9084             int nbSharedNodes = 0;
9085             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9086             while ( nodeIt->more() ) { // loop on free face nodes
9087               const SMDS_MeshNode* n =
9088                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9089               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9090               while ( invElemIt->more() ) {
9091                 const SMDS_MeshElement* e = invElemIt->next();
9092                 nbSharedNodes += faceSet->count( e );
9093                 nbSharedNodes += elemSet->count( e );
9094               }
9095             }
9096             if ( nbSharedNodes > maxNbNodes ) {
9097               maxNbNodes = nbSharedNodes;
9098               freeFaceList.erase( freeFaceList.begin(), fIt++ );
9099             }
9100             else if ( nbSharedNodes == maxNbNodes ) {
9101               fIt++;
9102             }
9103             else {
9104               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9105             }
9106           }
9107           if ( freeFaceList.size() > 1 )
9108           {
9109             // could not choose one face, use another way
9110             // choose a face most close to the bary center of the opposite side
9111             gp_XYZ aBC( 0., 0., 0. );
9112             set <const SMDS_MeshNode*> addedNodes;
9113             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9114             eIt = elemSet2->begin();
9115             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9116               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9117               while ( nodeIt->more() ) { // loop on free face nodes
9118                 const SMDS_MeshNode* n =
9119                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9120                 if ( addedNodes.insert( n ).second )
9121                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9122               }
9123             }
9124             aBC /= addedNodes.size();
9125             double minDist = DBL_MAX;
9126             fIt = freeFaceList.begin();
9127             while ( fIt != freeFaceList.end() ) { // loop on free faces
9128               double dist = 0;
9129               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9130               while ( nodeIt->more() ) { // loop on free face nodes
9131                 const SMDS_MeshNode* n =
9132                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9133                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9134                 dist += ( aBC - p ).SquareModulus();
9135               }
9136               if ( dist < minDist ) {
9137                 minDist = dist;
9138                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9139               }
9140               else
9141                 fIt = freeFaceList.erase( fIt++ );
9142             }
9143           }
9144         } // choose one of several free faces of a volume
9145
9146         if ( freeFaceList.size() == 1 ) {
9147           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9148           faceSet->insert( aFreeFace );
9149           // complete a node set with nodes of a found free face
9150           //           for ( iNode = 0; iNode < ; iNode++ )
9151           //             nodeSet->insert( fNodes[ iNode ] );
9152         }
9153
9154       } // loop on volumes of a side
9155
9156       //       // complete a set of faces if new nodes in a nodeSet appeared
9157       //       // ----------------------------------------------------------
9158       //       if ( nodeSetSize != nodeSet->size() ) {
9159       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9160       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9161       //           while ( fIt->more() ) { // loop on faces sharing a node
9162       //             const SMDS_MeshElement* f = fIt->next();
9163       //             if ( faceSet->find( f ) == faceSet->end() ) {
9164       //               // check if all nodes are in nodeSet and
9165       //               // complete setOfFaceNodeSet if they are
9166       //               set <const SMDS_MeshNode*> faceNodeSet;
9167       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9168       //               bool allInSet = true;
9169       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9170       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9171       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9172       //                   allInSet = false;
9173       //                 else
9174       //                   faceNodeSet.insert( n );
9175       //               }
9176       //               if ( allInSet ) {
9177       //                 faceSet->insert( f );
9178       //                 setOfFaceNodeSet.insert( faceNodeSet );
9179       //               }
9180       //             }
9181       //           }
9182       //         }
9183       //       }
9184     } // Create temporary faces, if there are volumes given
9185   } // loop on sides
9186
9187   if ( faceSet1.size() != faceSet2.size() ) {
9188     // delete temporary faces: they are in reverseElements of actual nodes
9189 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9190 //    while ( tmpFaceIt->more() )
9191 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9192 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9193 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9194 //      aMesh->RemoveElement(*tmpFaceIt);
9195     MESSAGE("Diff nb of faces");
9196     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9197   }
9198
9199   // ============================================================
9200   // 2. Find nodes to merge:
9201   //              bind a node to remove to a node to put instead
9202   // ============================================================
9203
9204   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9205   if ( theFirstNode1 != theFirstNode2 )
9206     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9207   if ( theSecondNode1 != theSecondNode2 )
9208     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9209
9210   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9211   set< long > linkIdSet; // links to process
9212   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9213
9214   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9215   list< NLink > linkList[2];
9216   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9217   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9218   // loop on links in linkList; find faces by links and append links
9219   // of the found faces to linkList
9220   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9221   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
9222   {
9223     NLink link[] = { *linkIt[0], *linkIt[1] };
9224     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9225     if ( !linkIdSet.count( linkID ) )
9226       continue;
9227
9228     // by links, find faces in the face sets,
9229     // and find indices of link nodes in the found faces;
9230     // in a face set, there is only one or no face sharing a link
9231     // ---------------------------------------------------------------
9232
9233     const SMDS_MeshElement* face[] = { 0, 0 };
9234     vector<const SMDS_MeshNode*> fnodes[2];
9235     int iLinkNode[2][2];
9236     TIDSortedElemSet avoidSet;
9237     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9238       const SMDS_MeshNode* n1 = link[iSide].first;
9239       const SMDS_MeshNode* n2 = link[iSide].second;
9240       //cout << "Side " << iSide << " ";
9241       //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
9242       // find a face by two link nodes
9243       face[ iSide ] = SMESH_MeshAlgos::FindFaceInSet( n1, n2,
9244                                                       *faceSetPtr[ iSide ], avoidSet,
9245                                                       &iLinkNode[iSide][0],
9246                                                       &iLinkNode[iSide][1] );
9247       if ( face[ iSide ])
9248       {
9249         //cout << " F " << face[ iSide]->GetID() <<endl;
9250         faceSetPtr[ iSide ]->erase( face[ iSide ]);
9251         // put face nodes to fnodes
9252         if ( face[ iSide ]->IsQuadratic() )
9253         {
9254           // use interlaced nodes iterator
9255           const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
9256           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9257           SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
9258           while ( nIter->more() )
9259             fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
9260         }
9261         else
9262         {
9263           fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
9264                                   face[ iSide ]->end_nodes() );
9265         }
9266         fnodes[ iSide ].push_back( fnodes[ iSide ].front());
9267       }
9268     }
9269
9270     // check similarity of elements of the sides
9271     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
9272       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9273       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9274         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9275       }
9276       else {
9277         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9278       }
9279       break; // do not return because it's necessary to remove tmp faces
9280     }
9281
9282     // set nodes to merge
9283     // -------------------
9284
9285     if ( face[0] && face[1] )  {
9286       const int nbNodes = face[0]->NbNodes();
9287       if ( nbNodes != face[1]->NbNodes() ) {
9288         MESSAGE("Diff nb of face nodes");
9289         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9290         break; // do not return because it s necessary to remove tmp faces
9291       }
9292       bool reverse[] = { false, false }; // order of nodes in the link
9293       for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9294         // analyse link orientation in faces
9295         int i1 = iLinkNode[ iSide ][ 0 ];
9296         int i2 = iLinkNode[ iSide ][ 1 ];
9297         reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9298       }
9299       int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
9300       int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
9301       for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
9302       {
9303         nReplaceMap.insert  ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
9304                                           fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
9305       }
9306
9307       // add other links of the faces to linkList
9308       // -----------------------------------------
9309
9310       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9311         linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
9312         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9313         if ( !iter_isnew.second ) { // already in a set: no need to process
9314           linkIdSet.erase( iter_isnew.first );
9315         }
9316         else // new in set == encountered for the first time: add
9317         {
9318           const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
9319           const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
9320           linkList[0].push_back ( NLink( n1, n2 ));
9321           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9322         }
9323       }
9324     } // 2 faces found
9325
9326     if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
9327       break;
9328
9329   } // loop on link lists
9330
9331   if ( aResult == SEW_OK &&
9332        ( //linkIt[0] != linkList[0].end() ||
9333          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9334     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9335              " " << (faceSetPtr[1]->empty()));
9336     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9337   }
9338
9339   // ====================================================================
9340   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9341   // ====================================================================
9342
9343   // delete temporary faces
9344 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9345 //  while ( tmpFaceIt->more() )
9346 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9347   list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9348   for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9349     aMesh->RemoveElement(*tmpFaceIt);
9350
9351   if ( aResult != SEW_OK)
9352     return aResult;
9353
9354   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9355   // loop on nodes replacement map
9356   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9357   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9358     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9359       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9360       nodeIDsToRemove.push_back( nToRemove->GetID() );
9361       // loop on elements sharing nToRemove
9362       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9363       while ( invElemIt->more() ) {
9364         const SMDS_MeshElement* e = invElemIt->next();
9365         // get a new suite of nodes: make replacement
9366         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9367         vector< const SMDS_MeshNode*> nodes( nbNodes );
9368         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9369         while ( nIt->more() ) {
9370           const SMDS_MeshNode* n =
9371             static_cast<const SMDS_MeshNode*>( nIt->next() );
9372           nnIt = nReplaceMap.find( n );
9373           if ( nnIt != nReplaceMap.end() ) {
9374             nbReplaced++;
9375             n = (*nnIt).second;
9376           }
9377           nodes[ i++ ] = n;
9378         }
9379         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9380         //         elemIDsToRemove.push_back( e->GetID() );
9381         //       else
9382         if ( nbReplaced )
9383           {
9384             SMDSAbs_ElementType etyp = e->GetType();
9385             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
9386             if (newElem)
9387               {
9388                 myLastCreatedElems.Append(newElem);
9389                 AddToSameGroups(newElem, e, aMesh);
9390                 int aShapeId = e->getshapeId();
9391                 if ( aShapeId )
9392                   {
9393                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
9394                   }
9395               }
9396             aMesh->RemoveElement(e);
9397           }
9398       }
9399     }
9400
9401   Remove( nodeIDsToRemove, true );
9402
9403   return aResult;
9404 }
9405
9406 //================================================================================
9407 /*!
9408  * \brief Find corresponding nodes in two sets of faces
9409  * \param theSide1 - first face set
9410  * \param theSide2 - second first face
9411  * \param theFirstNode1 - a boundary node of set 1
9412  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9413  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9414  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9415  * \param nReplaceMap - output map of corresponding nodes
9416  * \return bool  - is a success or not
9417  */
9418 //================================================================================
9419
9420 #ifdef _DEBUG_
9421 //#define DEBUG_MATCHING_NODES
9422 #endif
9423
9424 SMESH_MeshEditor::Sew_Error
9425 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9426                                     set<const SMDS_MeshElement*>& theSide2,
9427                                     const SMDS_MeshNode*          theFirstNode1,
9428                                     const SMDS_MeshNode*          theFirstNode2,
9429                                     const SMDS_MeshNode*          theSecondNode1,
9430                                     const SMDS_MeshNode*          theSecondNode2,
9431                                     TNodeNodeMap &                nReplaceMap)
9432 {
9433   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9434
9435   nReplaceMap.clear();
9436   if ( theFirstNode1 != theFirstNode2 )
9437     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9438   if ( theSecondNode1 != theSecondNode2 )
9439     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9440
9441   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9442   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9443
9444   list< NLink > linkList[2];
9445   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9446   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9447
9448   // loop on links in linkList; find faces by links and append links
9449   // of the found faces to linkList
9450   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9451   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9452     NLink link[] = { *linkIt[0], *linkIt[1] };
9453     if ( linkSet.find( link[0] ) == linkSet.end() )
9454       continue;
9455
9456     // by links, find faces in the face sets,
9457     // and find indices of link nodes in the found faces;
9458     // in a face set, there is only one or no face sharing a link
9459     // ---------------------------------------------------------------
9460
9461     const SMDS_MeshElement* face[] = { 0, 0 };
9462     list<const SMDS_MeshNode*> notLinkNodes[2];
9463     //bool reverse[] = { false, false }; // order of notLinkNodes
9464     int nbNodes[2];
9465     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9466     {
9467       const SMDS_MeshNode* n1 = link[iSide].first;
9468       const SMDS_MeshNode* n2 = link[iSide].second;
9469       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9470       set< const SMDS_MeshElement* > facesOfNode1;
9471       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9472       {
9473         // during a loop of the first node, we find all faces around n1,
9474         // during a loop of the second node, we find one face sharing both n1 and n2
9475         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9476         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9477         while ( fIt->more() ) { // loop on faces sharing a node
9478           const SMDS_MeshElement* f = fIt->next();
9479           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9480               ! facesOfNode1.insert( f ).second ) // f encounters twice
9481           {
9482             if ( face[ iSide ] ) {
9483               MESSAGE( "2 faces per link " );
9484               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9485             }
9486             face[ iSide ] = f;
9487             faceSet->erase( f );
9488
9489             // get not link nodes
9490             int nbN = f->NbNodes();
9491             if ( f->IsQuadratic() )
9492               nbN /= 2;
9493             nbNodes[ iSide ] = nbN;
9494             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9495             int i1 = f->GetNodeIndex( n1 );
9496             int i2 = f->GetNodeIndex( n2 );
9497             int iEnd = nbN, iBeg = -1, iDelta = 1;
9498             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9499             if ( reverse ) {
9500               std::swap( iEnd, iBeg ); iDelta = -1;
9501             }
9502             int i = i2;
9503             while ( true ) {
9504               i += iDelta;
9505               if ( i == iEnd ) i = iBeg + iDelta;
9506               if ( i == i1 ) break;
9507               nodes.push_back ( f->GetNode( i ) );
9508             }
9509           }
9510         }
9511       }
9512     }
9513     // check similarity of elements of the sides
9514     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9515       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9516       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9517         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9518       }
9519       else {
9520         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9521       }
9522     }
9523
9524     // set nodes to merge
9525     // -------------------
9526
9527     if ( face[0] && face[1] )  {
9528       if ( nbNodes[0] != nbNodes[1] ) {
9529         MESSAGE("Diff nb of face nodes");
9530         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9531       }
9532 #ifdef DEBUG_MATCHING_NODES
9533       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9534                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9535                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9536 #endif
9537       int nbN = nbNodes[0];
9538       {
9539         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9540         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9541         for ( int i = 0 ; i < nbN - 2; ++i ) {
9542 #ifdef DEBUG_MATCHING_NODES
9543           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9544 #endif
9545           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9546         }
9547       }
9548
9549       // add other links of the face 1 to linkList
9550       // -----------------------------------------
9551
9552       const SMDS_MeshElement* f0 = face[0];
9553       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9554       for ( int i = 0; i < nbN; i++ )
9555       {
9556         const SMDS_MeshNode* n2 = f0->GetNode( i );
9557         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9558           linkSet.insert( SMESH_TLink( n1, n2 ));
9559         if ( !iter_isnew.second ) { // already in a set: no need to process
9560           linkSet.erase( iter_isnew.first );
9561         }
9562         else // new in set == encountered for the first time: add
9563         {
9564 #ifdef DEBUG_MATCHING_NODES
9565           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9566                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9567 #endif
9568           linkList[0].push_back ( NLink( n1, n2 ));
9569           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9570         }
9571         n1 = n2;
9572       }
9573     } // 2 faces found
9574   } // loop on link lists
9575
9576   return SEW_OK;
9577 }
9578
9579 //================================================================================
9580 /*!
9581  * \brief Create elements equal (on same nodes) to given ones
9582  *  \param [in] theElements - a set of elems to duplicate. If it is empty, all
9583  *              elements of the uppest dimension are duplicated.
9584  */
9585 //================================================================================
9586
9587 void SMESH_MeshEditor::DoubleElements( const TIDSortedElemSet& theElements )
9588 {
9589   CrearLastCreated();
9590   SMESHDS_Mesh* mesh = GetMeshDS();
9591
9592   // get an element type and an iterator over elements
9593
9594   SMDSAbs_ElementType type;
9595   SMDS_ElemIteratorPtr elemIt;
9596   vector< const SMDS_MeshElement* > allElems;
9597   if ( theElements.empty() )
9598   {
9599     if ( mesh->NbNodes() == 0 )
9600       return;
9601     // get most complex type
9602     SMDSAbs_ElementType types[SMDSAbs_NbElementTypes] = {
9603       SMDSAbs_Volume, SMDSAbs_Face, SMDSAbs_Edge,
9604       SMDSAbs_0DElement, SMDSAbs_Ball, SMDSAbs_Node
9605     };
9606     for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
9607       if ( mesh->GetMeshInfo().NbElements( types[i] ))
9608       {
9609         type = types[i];
9610         break;
9611       }
9612     // put all elements in the vector <allElems>
9613     allElems.reserve( mesh->GetMeshInfo().NbElements( type ));
9614     elemIt = mesh->elementsIterator( type );
9615     while ( elemIt->more() )
9616       allElems.push_back( elemIt->next());
9617     elemIt = elemSetIterator( allElems );
9618   }
9619   else
9620   {
9621     type = (*theElements.begin())->GetType();
9622     elemIt = elemSetIterator( theElements );
9623   }
9624
9625   // duplicate elements
9626
9627   if ( type == SMDSAbs_Ball )
9628   {
9629     SMDS_UnstructuredGrid* vtkGrid = mesh->getGrid();
9630     while ( elemIt->more() )
9631     {
9632       const SMDS_MeshElement* elem = elemIt->next();
9633       if ( elem->GetType() != SMDSAbs_Ball )
9634         continue;
9635       if (( elem = mesh->AddBall( elem->GetNode(0),
9636                                   vtkGrid->GetBallDiameter( elem->getVtkId() ))))
9637         myLastCreatedElems.Append( elem );
9638     }
9639   }
9640   else
9641   {
9642     vector< const SMDS_MeshNode* > nodes;
9643     while ( elemIt->more() )
9644     {
9645       const SMDS_MeshElement* elem = elemIt->next();
9646       if ( elem->GetType() != type )
9647         continue;
9648
9649       nodes.assign( elem->begin_nodes(), elem->end_nodes() );
9650
9651       if ( type == SMDSAbs_Volume  && elem->GetVtkType() == VTK_POLYHEDRON )
9652       {
9653         std::vector<int> quantities =
9654           static_cast< const SMDS_VtkVolume* >( elem )->GetQuantities();
9655         elem = mesh->AddPolyhedralVolume( nodes, quantities );
9656       }
9657       else
9658       {
9659         AddElement( nodes, type, elem->IsPoly() );
9660         elem = 0; // myLastCreatedElems is already filled
9661       }
9662       if ( elem )
9663         myLastCreatedElems.Append( elem );
9664     }
9665   }
9666 }
9667
9668 //================================================================================
9669 /*!
9670   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9671   \param theElems - the list of elements (edges or faces) to be replicated
9672   The nodes for duplication could be found from these elements
9673   \param theNodesNot - list of nodes to NOT replicate
9674   \param theAffectedElems - the list of elements (cells and edges) to which the
9675   replicated nodes should be associated to.
9676   \return TRUE if operation has been completed successfully, FALSE otherwise
9677 */
9678 //================================================================================
9679
9680 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9681                                     const TIDSortedElemSet& theNodesNot,
9682                                     const TIDSortedElemSet& theAffectedElems )
9683 {
9684   myLastCreatedElems.Clear();
9685   myLastCreatedNodes.Clear();
9686
9687   if ( theElems.size() == 0 )
9688     return false;
9689
9690   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9691   if ( !aMeshDS )
9692     return false;
9693
9694   bool res = false;
9695   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9696   // duplicate elements and nodes
9697   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9698   // replce nodes by duplications
9699   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9700   return res;
9701 }
9702
9703 //================================================================================
9704 /*!
9705   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9706   \param theMeshDS - mesh instance
9707   \param theElems - the elements replicated or modified (nodes should be changed)
9708   \param theNodesNot - nodes to NOT replicate
9709   \param theNodeNodeMap - relation of old node to new created node
9710   \param theIsDoubleElem - flag os to replicate element or modify
9711   \return TRUE if operation has been completed successfully, FALSE otherwise
9712 */
9713 //================================================================================
9714
9715 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
9716                                     const TIDSortedElemSet& theElems,
9717                                     const TIDSortedElemSet& theNodesNot,
9718                                     std::map< const SMDS_MeshNode*,
9719                                     const SMDS_MeshNode* >& theNodeNodeMap,
9720                                     const bool theIsDoubleElem )
9721 {
9722   MESSAGE("doubleNodes");
9723   // iterate on through element and duplicate them (by nodes duplication)
9724   bool res = false;
9725   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9726   for ( ;  elemItr != theElems.end(); ++elemItr )
9727   {
9728     const SMDS_MeshElement* anElem = *elemItr;
9729     if (!anElem)
9730       continue;
9731
9732     bool isDuplicate = false;
9733     // duplicate nodes to duplicate element
9734     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9735     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9736     int ind = 0;
9737     while ( anIter->more() )
9738     {
9739
9740       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9741       SMDS_MeshNode* aNewNode = aCurrNode;
9742       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9743         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9744       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9745       {
9746         // duplicate node
9747         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9748         theNodeNodeMap[ aCurrNode ] = aNewNode;
9749         myLastCreatedNodes.Append( aNewNode );
9750       }
9751       isDuplicate |= (aCurrNode != aNewNode);
9752       newNodes[ ind++ ] = aNewNode;
9753     }
9754     if ( !isDuplicate )
9755       continue;
9756
9757     if ( theIsDoubleElem )
9758       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
9759     else
9760       {
9761       MESSAGE("ChangeElementNodes");
9762       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9763       }
9764     res = true;
9765   }
9766   return res;
9767 }
9768
9769 //================================================================================
9770 /*!
9771   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9772   \param theNodes - identifiers of nodes to be doubled
9773   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
9774          nodes. If list of element identifiers is empty then nodes are doubled but
9775          they not assigned to elements
9776   \return TRUE if operation has been completed successfully, FALSE otherwise
9777 */
9778 //================================================================================
9779
9780 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
9781                                     const std::list< int >& theListOfModifiedElems )
9782 {
9783   MESSAGE("DoubleNodes");
9784   myLastCreatedElems.Clear();
9785   myLastCreatedNodes.Clear();
9786
9787   if ( theListOfNodes.size() == 0 )
9788     return false;
9789
9790   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9791   if ( !aMeshDS )
9792     return false;
9793
9794   // iterate through nodes and duplicate them
9795
9796   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9797
9798   std::list< int >::const_iterator aNodeIter;
9799   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9800   {
9801     int aCurr = *aNodeIter;
9802     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9803     if ( !aNode )
9804       continue;
9805
9806     // duplicate node
9807
9808     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9809     if ( aNewNode )
9810     {
9811       anOldNodeToNewNode[ aNode ] = aNewNode;
9812       myLastCreatedNodes.Append( aNewNode );
9813     }
9814   }
9815
9816   // Create map of new nodes for modified elements
9817
9818   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9819
9820   std::list< int >::const_iterator anElemIter;
9821   for ( anElemIter = theListOfModifiedElems.begin();
9822         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9823   {
9824     int aCurr = *anElemIter;
9825     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9826     if ( !anElem )
9827       continue;
9828
9829     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9830
9831     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9832     int ind = 0;
9833     while ( anIter->more() )
9834     {
9835       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9836       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9837       {
9838         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9839         aNodeArr[ ind++ ] = aNewNode;
9840       }
9841       else
9842         aNodeArr[ ind++ ] = aCurrNode;
9843     }
9844     anElemToNodes[ anElem ] = aNodeArr;
9845   }
9846
9847   // Change nodes of elements
9848
9849   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9850     anElemToNodesIter = anElemToNodes.begin();
9851   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9852   {
9853     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9854     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9855     if ( anElem )
9856       {
9857       MESSAGE("ChangeElementNodes");
9858       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9859       }
9860   }
9861
9862   return true;
9863 }
9864
9865 namespace {
9866
9867   //================================================================================
9868   /*!
9869   \brief Check if element located inside shape
9870   \return TRUE if IN or ON shape, FALSE otherwise
9871   */
9872   //================================================================================
9873
9874   template<class Classifier>
9875   bool isInside(const SMDS_MeshElement* theElem,
9876                 Classifier&             theClassifier,
9877                 const double            theTol)
9878   {
9879     gp_XYZ centerXYZ (0, 0, 0);
9880     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9881     while (aNodeItr->more())
9882       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
9883
9884     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9885     theClassifier.Perform(aPnt, theTol);
9886     TopAbs_State aState = theClassifier.State();
9887     return (aState == TopAbs_IN || aState == TopAbs_ON );
9888   }
9889
9890   //================================================================================
9891   /*!
9892    * \brief Classifier of the 3D point on the TopoDS_Face
9893    *        with interaface suitable for isInside()
9894    */
9895   //================================================================================
9896
9897   struct _FaceClassifier
9898   {
9899     Extrema_ExtPS       _extremum;
9900     BRepAdaptor_Surface _surface;
9901     TopAbs_State        _state;
9902
9903     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9904     {
9905       _extremum.Initialize( _surface,
9906                             _surface.FirstUParameter(), _surface.LastUParameter(),
9907                             _surface.FirstVParameter(), _surface.LastVParameter(),
9908                             _surface.Tolerance(), _surface.Tolerance() );
9909     }
9910     void Perform(const gp_Pnt& aPnt, double theTol)
9911     {
9912       _state = TopAbs_OUT;
9913       _extremum.Perform(aPnt);
9914       if ( _extremum.IsDone() )
9915         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9916 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
9917           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9918 #else
9919           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9920 #endif
9921     }
9922     TopAbs_State State() const
9923     {
9924       return _state;
9925     }
9926   };
9927 }
9928
9929 //================================================================================
9930 /*!
9931   \brief Identify the elements that will be affected by node duplication (actual duplication is not performed.
9932   This method is the first step of DoubleNodeElemGroupsInRegion.
9933   \param theElems - list of groups of elements (edges or faces) to be replicated
9934   \param theNodesNot - list of groups of nodes not to replicated
9935   \param theShape - shape to detect affected elements (element which geometric center
9936          located on or inside shape).
9937          The replicated nodes should be associated to affected elements.
9938   \return groups of affected elements
9939   \sa DoubleNodeElemGroupsInRegion()
9940  */
9941 //================================================================================
9942
9943 bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
9944                                                    const TIDSortedElemSet& theNodesNot,
9945                                                    const TopoDS_Shape&     theShape,
9946                                                    TIDSortedElemSet&       theAffectedElems)
9947 {
9948   if ( theShape.IsNull() )
9949     return false;
9950
9951   const double aTol = Precision::Confusion();
9952   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
9953   auto_ptr<_FaceClassifier>              aFaceClassifier;
9954   if ( theShape.ShapeType() == TopAbs_SOLID )
9955   {
9956     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
9957     bsc3d->PerformInfinitePoint(aTol);
9958   }
9959   else if (theShape.ShapeType() == TopAbs_FACE )
9960   {
9961     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
9962   }
9963
9964   // iterates on indicated elements and get elements by back references from their nodes
9965   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9966   for ( ;  elemItr != theElems.end(); ++elemItr )
9967   {
9968     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
9969     if (!anElem)
9970       continue;
9971
9972     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
9973     while ( nodeItr->more() )
9974     {
9975       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
9976       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
9977         continue;
9978       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
9979       while ( backElemItr->more() )
9980       {
9981         const SMDS_MeshElement* curElem = backElemItr->next();
9982         if ( curElem && theElems.find(curElem) == theElems.end() &&
9983              ( bsc3d.get() ?
9984                isInside( curElem, *bsc3d, aTol ) :
9985                isInside( curElem, *aFaceClassifier, aTol )))
9986           theAffectedElems.insert( curElem );
9987       }
9988     }
9989   }
9990   return true;
9991 }
9992
9993 //================================================================================
9994 /*!
9995   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9996   \param theElems - group of of elements (edges or faces) to be replicated
9997   \param theNodesNot - group of nodes not to replicate
9998   \param theShape - shape to detect affected elements (element which geometric center
9999   located on or inside shape).
10000   The replicated nodes should be associated to affected elements.
10001   \return TRUE if operation has been completed successfully, FALSE otherwise
10002 */
10003 //================================================================================
10004
10005 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10006                                             const TIDSortedElemSet& theNodesNot,
10007                                             const TopoDS_Shape&     theShape )
10008 {
10009   if ( theShape.IsNull() )
10010     return false;
10011
10012   const double aTol = Precision::Confusion();
10013   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10014   auto_ptr<_FaceClassifier>              aFaceClassifier;
10015   if ( theShape.ShapeType() == TopAbs_SOLID )
10016   {
10017     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10018     bsc3d->PerformInfinitePoint(aTol);
10019   }
10020   else if (theShape.ShapeType() == TopAbs_FACE )
10021   {
10022     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10023   }
10024
10025   // iterates on indicated elements and get elements by back references from their nodes
10026   TIDSortedElemSet anAffected;
10027   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10028   for ( ;  elemItr != theElems.end(); ++elemItr )
10029   {
10030     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10031     if (!anElem)
10032       continue;
10033
10034     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10035     while ( nodeItr->more() )
10036     {
10037       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10038       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10039         continue;
10040       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10041       while ( backElemItr->more() )
10042       {
10043         const SMDS_MeshElement* curElem = backElemItr->next();
10044         if ( curElem && theElems.find(curElem) == theElems.end() &&
10045              ( bsc3d.get() ?
10046                isInside( curElem, *bsc3d, aTol ) :
10047                isInside( curElem, *aFaceClassifier, aTol )))
10048           anAffected.insert( curElem );
10049       }
10050     }
10051   }
10052   return DoubleNodes( theElems, theNodesNot, anAffected );
10053 }
10054
10055 /*!
10056  *  \brief compute an oriented angle between two planes defined by four points.
10057  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10058  *  @param p0 base of the rotation axe
10059  *  @param p1 extremity of the rotation axe
10060  *  @param g1 belongs to the first plane
10061  *  @param g2 belongs to the second plane
10062  */
10063 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10064 {
10065 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10066 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10067 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10068 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10069   gp_Vec vref(p0, p1);
10070   gp_Vec v1(p0, g1);
10071   gp_Vec v2(p0, g2);
10072   gp_Vec n1 = vref.Crossed(v1);
10073   gp_Vec n2 = vref.Crossed(v2);
10074   return n2.AngleWithRef(n1, vref);
10075 }
10076
10077 /*!
10078  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10079  *  The list of groups must contain at least two groups. The groups have to be disjoint: no common element into two different groups.
10080  * The nodes of the internal faces at the boundaries of the groups are doubled. Optionally, the internal faces are replaced by flat elements.
10081  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
10082  * The flat elements are stored in groups of volumes. These groups are named according to the position of the group in the list:
10083  * 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.
10084  * 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.
10085  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
10086  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
10087  * @param theElems - list of groups of volumes, where a group of volume is a set of
10088  * SMDS_MeshElements sorted by Id.
10089  * @param createJointElems - if TRUE, create the elements
10090  * @return TRUE if operation has been completed successfully, FALSE otherwise
10091  */
10092 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10093                                                      bool createJointElems)
10094 {
10095   MESSAGE("----------------------------------------------");
10096   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10097   MESSAGE("----------------------------------------------");
10098
10099   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10100   meshDS->BuildDownWardConnectivity(true);
10101   CHRONO(50);
10102   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10103
10104   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10105   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10106   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10107
10108   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10109   std::map<int,int>celldom; // cell vtkId --> domain
10110   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10111   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10112   faceDomains.clear();
10113   celldom.clear();
10114   cellDomains.clear();
10115   nodeDomains.clear();
10116   std::map<int,int> emptyMap;
10117   std::set<int> emptySet;
10118   emptyMap.clear();
10119
10120   MESSAGE(".. Number of domains :"<<theElems.size());
10121
10122   // Check if the domains do not share an element
10123   for (int idom = 0; idom < theElems.size()-1; idom++)
10124     {
10125 //       MESSAGE("... Check of domain #" << idom);
10126       const TIDSortedElemSet& domain = theElems[idom];
10127       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10128       for (; elemItr != domain.end(); ++elemItr)
10129         {
10130           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10131           int idombisdeb = idom + 1 ;
10132           for (int idombis = idombisdeb; idombis < theElems.size(); idombis++) // check if the element belongs to a domain further in the list
10133           {
10134             const TIDSortedElemSet& domainbis = theElems[idombis];
10135             if ( domainbis.count(anElem) )
10136             {
10137               MESSAGE(".... Domain #" << idom);
10138               MESSAGE(".... Domain #" << idombis);
10139               throw SALOME_Exception("The domains are not disjoint.");
10140               return false ;
10141             }
10142           }
10143         }
10144     }
10145
10146   for (int idom = 0; idom < theElems.size(); idom++)
10147     {
10148
10149       // --- build a map (face to duplicate --> volume to modify)
10150       //     with all the faces shared by 2 domains (group of elements)
10151       //     and corresponding volume of this domain, for each shared face.
10152       //     a volume has a face shared by 2 domains if it has a neighbor which is not in his domain.
10153
10154       MESSAGE("... Neighbors of domain #" << idom);
10155       const TIDSortedElemSet& domain = theElems[idom];
10156       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10157       for (; elemItr != domain.end(); ++elemItr)
10158         {
10159           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10160           if (!anElem)
10161             continue;
10162           int vtkId = anElem->getVtkId();
10163           //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
10164           int neighborsVtkIds[NBMAXNEIGHBORS];
10165           int downIds[NBMAXNEIGHBORS];
10166           unsigned char downTypes[NBMAXNEIGHBORS];
10167           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10168           for (int n = 0; n < nbNeighbors; n++)
10169             {
10170               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10171               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10172               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10173                 {
10174                   bool ok = false ;
10175                   for (int idombis = 0; idombis < theElems.size(); idombis++) // check if the neighbor belongs to another domain of the list
10176                   {
10177                     // MESSAGE("Domain " << idombis);
10178                     const TIDSortedElemSet& domainbis = theElems[idombis];
10179                     if ( domainbis.count(elem)) ok = true ; // neighbor is in a correct domain : face is kept
10180                   }
10181                   if ( ok ) // the characteristics of the face is stored
10182                   {
10183                     DownIdType face(downIds[n], downTypes[n]);
10184                     if (!faceDomains.count(face))
10185                       faceDomains[face] = emptyMap; // create an empty entry for face
10186                     if (!faceDomains[face].count(idom))
10187                       {
10188                         faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10189                         celldom[vtkId] = idom;
10190                         //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
10191                       }
10192                   }
10193                 }
10194             }
10195         }
10196     }
10197
10198   //MESSAGE("Number of shared faces " << faceDomains.size());
10199   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10200
10201   // --- explore the shared faces domain by domain,
10202   //     explore the nodes of the face and see if they belong to a cell in the domain,
10203   //     which has only a node or an edge on the border (not a shared face)
10204
10205   for (int idomain = 0; idomain < theElems.size(); idomain++)
10206     {
10207       //MESSAGE("Domain " << idomain);
10208       const TIDSortedElemSet& domain = theElems[idomain];
10209       itface = faceDomains.begin();
10210       for (; itface != faceDomains.end(); ++itface)
10211         {
10212           std::map<int, int> domvol = itface->second;
10213           if (!domvol.count(idomain))
10214             continue;
10215           DownIdType face = itface->first;
10216           //MESSAGE(" --- face " << face.cellId);
10217           std::set<int> oldNodes;
10218           oldNodes.clear();
10219           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10220           std::set<int>::iterator itn = oldNodes.begin();
10221           for (; itn != oldNodes.end(); ++itn)
10222             {
10223               int oldId = *itn;
10224               //MESSAGE("     node " << oldId);
10225               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10226               for (int i=0; i<l.ncells; i++)
10227                 {
10228                   int vtkId = l.cells[i];
10229                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10230                   if (!domain.count(anElem))
10231                     continue;
10232                   int vtkType = grid->GetCellType(vtkId);
10233                   int downId = grid->CellIdToDownId(vtkId);
10234                   if (downId < 0)
10235                     {
10236                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
10237                       continue; // not OK at this stage of the algorithm:
10238                                 //no cells created after BuildDownWardConnectivity
10239                     }
10240                   DownIdType aCell(downId, vtkType);
10241                   if (!cellDomains.count(aCell))
10242                     cellDomains[aCell] = emptyMap; // create an empty entry for cell
10243                   cellDomains[aCell][idomain] = vtkId;
10244                   celldom[vtkId] = idomain;
10245                   //MESSAGE("       cell " << vtkId << " domain " << idomain);
10246                 }
10247             }
10248         }
10249     }
10250
10251   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10252   //     for each shared face, get the nodes
10253   //     for each node, for each domain of the face, create a clone of the node
10254
10255   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10256   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10257   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
10258
10259   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10260   std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
10261   std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
10262
10263   MESSAGE(".. Duplication of the nodes");
10264   for (int idomain = 0; idomain < theElems.size(); idomain++)
10265     {
10266       itface = faceDomains.begin();
10267       for (; itface != faceDomains.end(); ++itface)
10268         {
10269           std::map<int, int> domvol = itface->second;
10270           if (!domvol.count(idomain))
10271             continue;
10272           DownIdType face = itface->first;
10273           //MESSAGE(" --- face " << face.cellId);
10274           std::set<int> oldNodes;
10275           oldNodes.clear();
10276           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10277           std::set<int>::iterator itn = oldNodes.begin();
10278           for (; itn != oldNodes.end(); ++itn)
10279             {
10280               int oldId = *itn;
10281               //MESSAGE("-+-+-a node " << oldId);
10282               if (!nodeDomains.count(oldId))
10283                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10284               if (nodeDomains[oldId].empty())
10285                 {
10286                   nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
10287                   //MESSAGE("-+-+-b     oldNode " << oldId << " domain " << idomain);
10288                 }
10289               std::map<int, int>::iterator itdom = domvol.begin();
10290               for (; itdom != domvol.end(); ++itdom)
10291                 {
10292                   int idom = itdom->first;
10293                   //MESSAGE("         domain " << idom);
10294                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
10295                     {
10296                       if (nodeDomains[oldId].size() >= 2) // a multiple node
10297                         {
10298                           vector<int> orderedDoms;
10299                           //MESSAGE("multiple node " << oldId);
10300                           if (mutipleNodes.count(oldId))
10301                             orderedDoms = mutipleNodes[oldId];
10302                           else
10303                             {
10304                               map<int,int>::iterator it = nodeDomains[oldId].begin();
10305                               for (; it != nodeDomains[oldId].end(); ++it)
10306                                 orderedDoms.push_back(it->first);
10307                             }
10308                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
10309                           //stringstream txt;
10310                           //for (int i=0; i<orderedDoms.size(); i++)
10311                           //  txt << orderedDoms[i] << " ";
10312                           //MESSAGE("orderedDoms " << txt.str());
10313                           mutipleNodes[oldId] = orderedDoms;
10314                         }
10315                       double *coords = grid->GetPoint(oldId);
10316                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10317                       int newId = newNode->getVtkId();
10318                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
10319                       //MESSAGE("-+-+-c     oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
10320                     }
10321                 }
10322             }
10323         }
10324     }
10325
10326   MESSAGE(".. Creation of elements");
10327   for (int idomain = 0; idomain < theElems.size(); idomain++)
10328     {
10329       itface = faceDomains.begin();
10330       for (; itface != faceDomains.end(); ++itface)
10331         {
10332           std::map<int, int> domvol = itface->second;
10333           if (!domvol.count(idomain))
10334             continue;
10335           DownIdType face = itface->first;
10336           //MESSAGE(" --- face " << face.cellId);
10337           std::set<int> oldNodes;
10338           oldNodes.clear();
10339           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10340           int nbMultipleNodes = 0;
10341           std::set<int>::iterator itn = oldNodes.begin();
10342           for (; itn != oldNodes.end(); ++itn)
10343             {
10344               int oldId = *itn;
10345               if (mutipleNodes.count(oldId))
10346                 nbMultipleNodes++;
10347             }
10348           if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains
10349             {
10350               //MESSAGE("multiple Nodes detected on a shared face");
10351               int downId = itface->first.cellId;
10352               unsigned char cellType = itface->first.cellType;
10353               // --- shared edge or shared face ?
10354               if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
10355                 {
10356                   int nodes[3];
10357                   int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
10358                   for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
10359                     if (mutipleNodes.count(nodes[i]))
10360                       if (!mutipleNodesToFace.count(nodes[i]))
10361                         mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
10362                 }
10363               else // shared face (between two volumes)
10364                 {
10365                   int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
10366                   const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
10367                   const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
10368                   for (int ie =0; ie < nbEdges; ie++)
10369                     {
10370                       int nodes[3];
10371                       int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
10372                       if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
10373                         {
10374                           vector<int> vn0 = mutipleNodes[nodes[0]];
10375                           vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
10376                           vector<int> doms;
10377                           for (int i0 = 0; i0 < vn0.size(); i0++)
10378                             for (int i1 = 0; i1 < vn1.size(); i1++)
10379                               if (vn0[i0] == vn1[i1])
10380                                 doms.push_back(vn0[i0]);
10381                           if (doms.size() >2)
10382                             {
10383                               //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
10384                               double *coords = grid->GetPoint(nodes[0]);
10385                               gp_Pnt p0(coords[0], coords[1], coords[2]);
10386                               coords = grid->GetPoint(nodes[nbNodes - 1]);
10387                               gp_Pnt p1(coords[0], coords[1], coords[2]);
10388                               gp_Pnt gref;
10389                               int vtkVolIds[1000];  // an edge can belong to a lot of volumes
10390                               map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
10391                               map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
10392                               int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
10393                               for (int id=0; id < doms.size(); id++)
10394                                 {
10395                                   int idom = doms[id];
10396                                   for (int ivol=0; ivol<nbvol; ivol++)
10397                                     {
10398                                       int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
10399                                       SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
10400                                       if (theElems[idom].count(elem))
10401                                         {
10402                                           SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
10403                                           domvol[idom] = svol;
10404                                           //MESSAGE("  domain " << idom << " volume " << elem->GetID());
10405                                           double values[3];
10406                                           vtkIdType npts = 0;
10407                                           vtkIdType* pts = 0;
10408                                           grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
10409                                           SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
10410                                           if (id ==0)
10411                                             {
10412                                               gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
10413                                               angleDom[idom] = 0;
10414                                             }
10415                                           else
10416                                             {
10417                                               gp_Pnt g(values[0], values[1], values[2]);
10418                                               angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
10419                                               //MESSAGE("  angle=" << angleDom[idom]);
10420                                             }
10421                                           break;
10422                                         }
10423                                     }
10424                                 }
10425                               map<double, int> sortedDom; // sort domains by angle
10426                               for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
10427                                 sortedDom[ia->second] = ia->first;
10428                               vector<int> vnodes;
10429                               vector<int> vdom;
10430                               for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
10431                                 {
10432                                   vdom.push_back(ib->second);
10433                                   //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
10434                                 }
10435                               for (int ino = 0; ino < nbNodes; ino++)
10436                                 vnodes.push_back(nodes[ino]);
10437                               edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
10438                             }
10439                         }
10440                     }
10441                 }
10442             }
10443         }
10444     }
10445
10446   // --- iterate on shared faces (volumes to modify, face to extrude)
10447   //     get node id's of the face (id SMDS = id VTK)
10448   //     create flat element with old and new nodes if requested
10449
10450   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
10451   //     (domain1 X domain2) = domain1 + MAXINT*domain2
10452
10453   std::map<int, std::map<long,int> > nodeQuadDomains;
10454   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10455
10456   MESSAGE(".. Creation of elements: simple junction");
10457   if (createJointElems)
10458     {
10459       int idg;
10460       string joints2DName = "joints2D";
10461       mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg);
10462       SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
10463       string joints3DName = "joints3D";
10464       mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg);
10465       SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
10466
10467       itface = faceDomains.begin();
10468       for (; itface != faceDomains.end(); ++itface)
10469         {
10470           DownIdType face = itface->first;
10471           std::set<int> oldNodes;
10472           std::set<int>::iterator itn;
10473           oldNodes.clear();
10474           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10475
10476           std::map<int, int> domvol = itface->second;
10477           std::map<int, int>::iterator itdom = domvol.begin();
10478           int dom1 = itdom->first;
10479           int vtkVolId = itdom->second;
10480           itdom++;
10481           int dom2 = itdom->first;
10482           SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
10483                                                              nodeQuadDomains);
10484           stringstream grpname;
10485           grpname << "j_";
10486           if (dom1 < dom2)
10487             grpname << dom1 << "_" << dom2;
10488           else
10489             grpname << dom2 << "_" << dom1;
10490           string namegrp = grpname.str();
10491           if (!mapOfJunctionGroups.count(namegrp))
10492             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
10493           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10494           if (sgrp)
10495             sgrp->Add(vol->GetID());
10496           if (vol->GetType() == SMDSAbs_Volume)
10497             joints3DGrp->Add(vol->GetID());
10498           else if (vol->GetType() == SMDSAbs_Face)
10499             joints2DGrp->Add(vol->GetID());
10500         }
10501     }
10502
10503   // --- create volumes on multiple domain intersection if requested
10504   //     iterate on mutipleNodesToFace
10505   //     iterate on edgesMultiDomains
10506
10507   MESSAGE(".. Creation of elements: multiple junction");
10508   if (createJointElems)
10509     {
10510       // --- iterate on mutipleNodesToFace
10511
10512       std::map<int, std::vector<int> >::iterator itn =  mutipleNodesToFace.begin();
10513       for (; itn != mutipleNodesToFace.end(); ++itn)
10514         {
10515           int node = itn->first;
10516           vector<int> orderDom = itn->second;
10517           vector<vtkIdType> orderedNodes;
10518           for (int idom = 0; idom <orderDom.size(); idom++)
10519             orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
10520             SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
10521
10522             stringstream grpname;
10523             grpname << "m2j_";
10524             grpname << 0 << "_" << 0;
10525             int idg;
10526             string namegrp = grpname.str();
10527             if (!mapOfJunctionGroups.count(namegrp))
10528               mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
10529             SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10530             if (sgrp)
10531               sgrp->Add(face->GetID());
10532         }
10533
10534       // --- iterate on edgesMultiDomains
10535
10536       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
10537       for (; ite != edgesMultiDomains.end(); ++ite)
10538         {
10539           vector<int> nodes = ite->first;
10540           vector<int> orderDom = ite->second;
10541           vector<vtkIdType> orderedNodes;
10542           if (nodes.size() == 2)
10543             {
10544               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
10545               for (int ino=0; ino < nodes.size(); ino++)
10546                 if (orderDom.size() == 3)
10547                   for (int idom = 0; idom <orderDom.size(); idom++)
10548                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
10549                 else
10550                   for (int idom = orderDom.size()-1; idom >=0; idom--)
10551                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
10552               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
10553
10554               int idg;
10555               string namegrp = "jointsMultiples";
10556               if (!mapOfJunctionGroups.count(namegrp))
10557                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
10558               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10559               if (sgrp)
10560                 sgrp->Add(vol->GetID());
10561             }
10562           else
10563             {
10564               INFOS("Quadratic multiple joints not implemented");
10565               // TODO quadratic nodes
10566             }
10567         }
10568     }
10569
10570   // --- list the explicit faces and edges of the mesh that need to be modified,
10571   //     i.e. faces and edges built with one or more duplicated nodes.
10572   //     associate these faces or edges to their corresponding domain.
10573   //     only the first domain found is kept when a face or edge is shared
10574
10575   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
10576   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
10577   faceOrEdgeDom.clear();
10578   feDom.clear();
10579
10580   MESSAGE(".. Modification of elements");
10581   for (int idomain = 0; idomain < theElems.size(); idomain++)
10582     {
10583       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
10584       for (; itnod != nodeDomains.end(); ++itnod)
10585         {
10586           int oldId = itnod->first;
10587           //MESSAGE("     node " << oldId);
10588           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10589           for (int i = 0; i < l.ncells; i++)
10590             {
10591               int vtkId = l.cells[i];
10592               int vtkType = grid->GetCellType(vtkId);
10593               int downId = grid->CellIdToDownId(vtkId);
10594               if (downId < 0)
10595                 continue; // new cells: not to be modified
10596               DownIdType aCell(downId, vtkType);
10597               int volParents[1000];
10598               int nbvol = grid->GetParentVolumes(volParents, vtkId);
10599               for (int j = 0; j < nbvol; j++)
10600                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
10601                   if (!feDom.count(vtkId))
10602                     {
10603                       feDom[vtkId] = idomain;
10604                       faceOrEdgeDom[aCell] = emptyMap;
10605                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
10606                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
10607                       //        << " type " << vtkType << " downId " << downId);
10608                     }
10609             }
10610         }
10611     }
10612
10613   // --- iterate on shared faces (volumes to modify, face to extrude)
10614   //     get node id's of the face
10615   //     replace old nodes by new nodes in volumes, and update inverse connectivity
10616
10617   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
10618   for (int m=0; m<3; m++)
10619     {
10620       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
10621       itface = (*amap).begin();
10622       for (; itface != (*amap).end(); ++itface)
10623         {
10624           DownIdType face = itface->first;
10625           std::set<int> oldNodes;
10626           std::set<int>::iterator itn;
10627           oldNodes.clear();
10628           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10629           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
10630           std::map<int, int> localClonedNodeIds;
10631
10632           std::map<int, int> domvol = itface->second;
10633           std::map<int, int>::iterator itdom = domvol.begin();
10634           for (; itdom != domvol.end(); ++itdom)
10635             {
10636               int idom = itdom->first;
10637               int vtkVolId = itdom->second;
10638               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
10639               localClonedNodeIds.clear();
10640               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10641                 {
10642                   int oldId = *itn;
10643                   if (nodeDomains[oldId].count(idom))
10644                     {
10645                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10646                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
10647                     }
10648                 }
10649               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10650             }
10651         }
10652     }
10653
10654   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
10655   grid->BuildLinks();
10656
10657   CHRONOSTOP(50);
10658   counters::stats();
10659   return true;
10660 }
10661
10662 /*!
10663  * \brief Double nodes on some external faces and create flat elements.
10664  * Flat elements are mainly used by some types of mechanic calculations.
10665  *
10666  * Each group of the list must be constituted of faces.
10667  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10668  * @param theElems - list of groups of faces, where a group of faces is a set of
10669  * SMDS_MeshElements sorted by Id.
10670  * @return TRUE if operation has been completed successfully, FALSE otherwise
10671  */
10672 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
10673 {
10674   MESSAGE("-------------------------------------------------");
10675   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
10676   MESSAGE("-------------------------------------------------");
10677
10678   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10679
10680   // --- For each group of faces
10681   //     duplicate the nodes, create a flat element based on the face
10682   //     replace the nodes of the faces by their clones
10683
10684   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
10685   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
10686   clonedNodes.clear();
10687   intermediateNodes.clear();
10688   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10689   mapOfJunctionGroups.clear();
10690
10691   for (int idom = 0; idom < theElems.size(); idom++)
10692     {
10693       const TIDSortedElemSet& domain = theElems[idom];
10694       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10695       for (; elemItr != domain.end(); ++elemItr)
10696         {
10697           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10698           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
10699           if (!aFace)
10700             continue;
10701           // MESSAGE("aFace=" << aFace->GetID());
10702           bool isQuad = aFace->IsQuadratic();
10703           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
10704
10705           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
10706
10707           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
10708           while (nodeIt->more())
10709             {
10710               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
10711               bool isMedium = isQuad && (aFace->IsMediumNode(node));
10712               if (isMedium)
10713                 ln2.push_back(node);
10714               else
10715                 ln0.push_back(node);
10716
10717               const SMDS_MeshNode* clone = 0;
10718               if (!clonedNodes.count(node))
10719                 {
10720                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
10721                   clonedNodes[node] = clone;
10722                 }
10723               else
10724                 clone = clonedNodes[node];
10725
10726               if (isMedium)
10727                 ln3.push_back(clone);
10728               else
10729                 ln1.push_back(clone);
10730
10731               const SMDS_MeshNode* inter = 0;
10732               if (isQuad && (!isMedium))
10733                 {
10734                   if (!intermediateNodes.count(node))
10735                     {
10736                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
10737                       intermediateNodes[node] = inter;
10738                     }
10739                   else
10740                     inter = intermediateNodes[node];
10741                   ln4.push_back(inter);
10742                 }
10743             }
10744
10745           // --- extrude the face
10746
10747           vector<const SMDS_MeshNode*> ln;
10748           SMDS_MeshVolume* vol = 0;
10749           vtkIdType aType = aFace->GetVtkType();
10750           switch (aType)
10751           {
10752             case VTK_TRIANGLE:
10753               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
10754               // MESSAGE("vol prism " << vol->GetID());
10755               ln.push_back(ln1[0]);
10756               ln.push_back(ln1[1]);
10757               ln.push_back(ln1[2]);
10758               break;
10759             case VTK_QUAD:
10760               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
10761               // MESSAGE("vol hexa " << vol->GetID());
10762               ln.push_back(ln1[0]);
10763               ln.push_back(ln1[1]);
10764               ln.push_back(ln1[2]);
10765               ln.push_back(ln1[3]);
10766               break;
10767             case VTK_QUADRATIC_TRIANGLE:
10768               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
10769                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
10770               // MESSAGE("vol quad prism " << vol->GetID());
10771               ln.push_back(ln1[0]);
10772               ln.push_back(ln1[1]);
10773               ln.push_back(ln1[2]);
10774               ln.push_back(ln3[0]);
10775               ln.push_back(ln3[1]);
10776               ln.push_back(ln3[2]);
10777               break;
10778             case VTK_QUADRATIC_QUAD:
10779 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
10780 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
10781 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
10782               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
10783                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
10784                                       ln4[0], ln4[1], ln4[2], ln4[3]);
10785               // MESSAGE("vol quad hexa " << vol->GetID());
10786               ln.push_back(ln1[0]);
10787               ln.push_back(ln1[1]);
10788               ln.push_back(ln1[2]);
10789               ln.push_back(ln1[3]);
10790               ln.push_back(ln3[0]);
10791               ln.push_back(ln3[1]);
10792               ln.push_back(ln3[2]);
10793               ln.push_back(ln3[3]);
10794               break;
10795             case VTK_POLYGON:
10796               break;
10797             default:
10798               break;
10799           }
10800
10801           if (vol)
10802             {
10803               stringstream grpname;
10804               grpname << "jf_";
10805               grpname << idom;
10806               int idg;
10807               string namegrp = grpname.str();
10808               if (!mapOfJunctionGroups.count(namegrp))
10809                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
10810               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10811               if (sgrp)
10812                 sgrp->Add(vol->GetID());
10813             }
10814
10815           // --- modify the face
10816
10817           aFace->ChangeNodes(&ln[0], ln.size());
10818         }
10819     }
10820   return true;
10821 }
10822
10823 /*!
10824  *  \brief identify all the elements around a geom shape, get the faces delimiting the hole
10825  *  Build groups of volume to remove, groups of faces to replace on the skin of the object,
10826  *  groups of faces to remove inside the object, (idem edges).
10827  *  Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape)
10828  */
10829 void SMESH_MeshEditor::CreateHoleSkin(double radius,
10830                                       const TopoDS_Shape& theShape,
10831                                       SMESH_NodeSearcher* theNodeSearcher,
10832                                       const char* groupName,
10833                                       std::vector<double>&   nodesCoords,
10834                                       std::vector<std::vector<int> >& listOfListOfNodes)
10835 {
10836   MESSAGE("--------------------------------");
10837   MESSAGE("SMESH_MeshEditor::CreateHoleSkin");
10838   MESSAGE("--------------------------------");
10839
10840   // --- zone of volumes to remove is given :
10841   //     1 either by a geom shape (one or more vertices) and a radius,
10842   //     2 either by a group of nodes (representative of the shape)to use with the radius,
10843   //     3 either by a group of nodes where all the elements build on one of this nodes are to remove,
10844   //     In the case 2, the group of nodes is an external group of nodes from another mesh,
10845   //     In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter),
10846   //     defined by it's name.
10847
10848   SMESHDS_GroupBase* groupDS = 0;
10849   SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups();
10850   while ( groupIt->more() )
10851     {
10852       groupDS = 0;
10853       SMESH_Group * group = groupIt->next();
10854       if ( !group ) continue;
10855       groupDS = group->GetGroupDS();
10856       if ( !groupDS || groupDS->IsEmpty() ) continue;
10857       std::string grpName = group->GetName();
10858       //MESSAGE("grpName=" << grpName);
10859       if (grpName == groupName)
10860         break;
10861       else
10862         groupDS = 0;
10863     }
10864
10865   bool isNodeGroup = false;
10866   bool isNodeCoords = false;
10867   if (groupDS)
10868     {
10869       if (groupDS->GetType() != SMDSAbs_Node)
10870         return;
10871       isNodeGroup = true;     // a group of nodes exists and it is in this mesh
10872     }
10873
10874   if (nodesCoords.size() > 0)
10875     isNodeCoords = true; // a list o nodes given by their coordinates
10876   //MESSAGE("---" << isNodeGroup << " " << isNodeCoords);
10877
10878   // --- define groups to build
10879
10880   int idg; // --- group of SMDS volumes
10881   string grpvName = groupName;
10882   grpvName += "_vol";
10883   SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
10884   if (!grp)
10885     {
10886       MESSAGE("group not created " << grpvName);
10887       return;
10888     }
10889   SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
10890
10891   int idgs; // --- group of SMDS faces on the skin
10892   string grpsName = groupName;
10893   grpsName += "_skin";
10894   SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
10895   if (!grps)
10896     {
10897       MESSAGE("group not created " << grpsName);
10898       return;
10899     }
10900   SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
10901
10902   int idgi; // --- group of SMDS faces internal (several shapes)
10903   string grpiName = groupName;
10904   grpiName += "_internalFaces";
10905   SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
10906   if (!grpi)
10907     {
10908       MESSAGE("group not created " << grpiName);
10909       return;
10910     }
10911   SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
10912
10913   int idgei; // --- group of SMDS faces internal (several shapes)
10914   string grpeiName = groupName;
10915   grpeiName += "_internalEdges";
10916   SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
10917   if (!grpei)
10918     {
10919       MESSAGE("group not created " << grpeiName);
10920       return;
10921     }
10922   SMESHDS_Group *sgrpei = dynamic_cast<SMESHDS_Group*>(grpei->GetGroupDS());
10923
10924   // --- build downward connectivity
10925
10926   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10927   meshDS->BuildDownWardConnectivity(true);
10928   SMDS_UnstructuredGrid* grid = meshDS->getGrid();
10929
10930   // --- set of volumes detected inside
10931
10932   std::set<int> setOfInsideVol;
10933   std::set<int> setOfVolToCheck;
10934
10935   std::vector<gp_Pnt> gpnts;
10936   gpnts.clear();
10937
10938   if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
10939     {
10940       MESSAGE("group of nodes provided");
10941       SMDS_ElemIteratorPtr elemIt = groupDS->GetElements();
10942       while ( elemIt->more() )
10943         {
10944           const SMDS_MeshElement* elem = elemIt->next();
10945           if (!elem)
10946             continue;
10947           const SMDS_MeshNode* node = dynamic_cast<const SMDS_MeshNode*>(elem);
10948           if (!node)
10949             continue;
10950           SMDS_MeshElement* vol = 0;
10951           SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume);
10952           while (volItr->more())
10953             {
10954               vol = (SMDS_MeshElement*)volItr->next();
10955               setOfInsideVol.insert(vol->getVtkId());
10956               sgrp->Add(vol->GetID());
10957             }
10958         }
10959     }
10960   else if (isNodeCoords)
10961     {
10962       MESSAGE("list of nodes coordinates provided");
10963       int i = 0;
10964       int k = 0;
10965       while (i < nodesCoords.size()-2)
10966         {
10967           double x = nodesCoords[i++];
10968           double y = nodesCoords[i++];
10969           double z = nodesCoords[i++];
10970           gp_Pnt p = gp_Pnt(x, y ,z);
10971           gpnts.push_back(p);
10972           MESSAGE("TopoDS_Vertex " << k << " " << p.X() << " " << p.Y() << " " << p.Z());
10973           k++;
10974         }
10975     }
10976   else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius
10977     {
10978       MESSAGE("no group of nodes provided, using vertices from geom shape, and radius");
10979       TopTools_IndexedMapOfShape vertexMap;
10980       TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap );
10981       gp_Pnt p = gp_Pnt(0,0,0);
10982       if (vertexMap.Extent() < 1)
10983         return;
10984
10985       for ( int i = 1; i <= vertexMap.Extent(); ++i )
10986         {
10987           const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i ));
10988           p = BRep_Tool::Pnt(vertex);
10989           gpnts.push_back(p);
10990           MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z());
10991         }
10992     }
10993
10994   if (gpnts.size() > 0)
10995     {
10996       int nodeId = 0;
10997       const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
10998       if (startNode)
10999         nodeId = startNode->GetID();
11000       MESSAGE("nodeId " << nodeId);
11001
11002       double radius2 = radius*radius;
11003       MESSAGE("radius2 " << radius2);
11004
11005       // --- volumes on start node
11006
11007       setOfVolToCheck.clear();
11008       SMDS_MeshElement* startVol = 0;
11009       SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
11010       while (volItr->more())
11011         {
11012           startVol = (SMDS_MeshElement*)volItr->next();
11013           setOfVolToCheck.insert(startVol->getVtkId());
11014         }
11015       if (setOfVolToCheck.empty())
11016         {
11017           MESSAGE("No volumes found");
11018           return;
11019         }
11020
11021       // --- starting with central volumes then their neighbors, check if they are inside
11022       //     or outside the domain, until no more new neighbor volume is inside.
11023       //     Fill the group of inside volumes
11024
11025       std::map<int, double> mapOfNodeDistance2;
11026       mapOfNodeDistance2.clear();
11027       std::set<int> setOfOutsideVol;
11028       while (!setOfVolToCheck.empty())
11029         {
11030           std::set<int>::iterator it = setOfVolToCheck.begin();
11031           int vtkId = *it;
11032           MESSAGE("volume to check,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11033           bool volInside = false;
11034           vtkIdType npts = 0;
11035           vtkIdType* pts = 0;
11036           grid->GetCellPoints(vtkId, npts, pts);
11037           for (int i=0; i<npts; i++)
11038             {
11039               double distance2 = 0;
11040               if (mapOfNodeDistance2.count(pts[i]))
11041                 {
11042                   distance2 = mapOfNodeDistance2[pts[i]];
11043                   MESSAGE("point " << pts[i] << " distance2 " << distance2);
11044                 }
11045               else
11046                 {
11047                   double *coords = grid->GetPoint(pts[i]);
11048                   gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
11049                   distance2 = 1.E40;
11050                   for (int j=0; j<gpnts.size(); j++)
11051                     {
11052                       double d2 = aPoint.SquareDistance(gpnts[j]);
11053                       if (d2 < distance2)
11054                         {
11055                           distance2 = d2;
11056                           if (distance2 < radius2)
11057                             break;
11058                         }
11059                     }
11060                   mapOfNodeDistance2[pts[i]] = distance2;
11061                   MESSAGE("  point "  << pts[i]  << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " <<  coords[2]);
11062                 }
11063               if (distance2 < radius2)
11064                 {
11065                   volInside = true; // one or more nodes inside the domain
11066                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
11067                   break;
11068                 }
11069             }
11070           if (volInside)
11071             {
11072               setOfInsideVol.insert(vtkId);
11073               MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11074               int neighborsVtkIds[NBMAXNEIGHBORS];
11075               int downIds[NBMAXNEIGHBORS];
11076               unsigned char downTypes[NBMAXNEIGHBORS];
11077               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11078               for (int n = 0; n < nbNeighbors; n++)
11079                 if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n]))
11080                   setOfVolToCheck.insert(neighborsVtkIds[n]);
11081             }
11082           else
11083             {
11084               setOfOutsideVol.insert(vtkId);
11085               MESSAGE("  volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11086             }
11087           setOfVolToCheck.erase(vtkId);
11088         }
11089     }
11090
11091   // --- for outside hexahedrons, check if they have more than one neighbor volume inside
11092   //     If yes, add the volume to the inside set
11093
11094   bool addedInside = true;
11095   std::set<int> setOfVolToReCheck;
11096   while (addedInside)
11097     {
11098       MESSAGE(" --------------------------- re check");
11099       addedInside = false;
11100       std::set<int>::iterator itv = setOfInsideVol.begin();
11101       for (; itv != setOfInsideVol.end(); ++itv)
11102         {
11103           int vtkId = *itv;
11104           int neighborsVtkIds[NBMAXNEIGHBORS];
11105           int downIds[NBMAXNEIGHBORS];
11106           unsigned char downTypes[NBMAXNEIGHBORS];
11107           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11108           for (int n = 0; n < nbNeighbors; n++)
11109             if (!setOfInsideVol.count(neighborsVtkIds[n]))
11110               setOfVolToReCheck.insert(neighborsVtkIds[n]);
11111         }
11112       setOfVolToCheck = setOfVolToReCheck;
11113       setOfVolToReCheck.clear();
11114       while  (!setOfVolToCheck.empty())
11115         {
11116           std::set<int>::iterator it = setOfVolToCheck.begin();
11117           int vtkId = *it;
11118           if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON)
11119             {
11120               MESSAGE("volume to recheck,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11121               int countInside = 0;
11122               int neighborsVtkIds[NBMAXNEIGHBORS];
11123               int downIds[NBMAXNEIGHBORS];
11124               unsigned char downTypes[NBMAXNEIGHBORS];
11125               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11126               for (int n = 0; n < nbNeighbors; n++)
11127                 if (setOfInsideVol.count(neighborsVtkIds[n]))
11128                   countInside++;
11129               MESSAGE("countInside " << countInside);
11130               if (countInside > 1)
11131                 {
11132                   MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11133                   setOfInsideVol.insert(vtkId);
11134                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
11135                   addedInside = true;
11136                 }
11137               else
11138                 setOfVolToReCheck.insert(vtkId);
11139             }
11140           setOfVolToCheck.erase(vtkId);
11141         }
11142     }
11143
11144   // --- map of Downward faces at the boundary, inside the global volume
11145   //     map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin)
11146   //     fill group of SMDS faces inside the volume (when several volume shapes)
11147   //     fill group of SMDS faces on the skin of the global volume (if skin)
11148
11149   std::map<DownIdType, int, DownIdCompare> boundaryFaces; // boundary faces inside the volume --> corresponding cell
11150   std::map<DownIdType, int, DownIdCompare> skinFaces;     // faces on the skin of the global volume --> corresponding cell
11151   std::set<int>::iterator it = setOfInsideVol.begin();
11152   for (; it != setOfInsideVol.end(); ++it)
11153     {
11154       int vtkId = *it;
11155       //MESSAGE("  vtkId " << vtkId  << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11156       int neighborsVtkIds[NBMAXNEIGHBORS];
11157       int downIds[NBMAXNEIGHBORS];
11158       unsigned char downTypes[NBMAXNEIGHBORS];
11159       int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true);
11160       for (int n = 0; n < nbNeighbors; n++)
11161         {
11162           int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n]));
11163           if (neighborDim == 3)
11164             {
11165               if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary
11166                 {
11167                   DownIdType face(downIds[n], downTypes[n]);
11168                   boundaryFaces[face] = vtkId;
11169                 }
11170               // if the face between to volumes is in the mesh, get it (internal face between shapes)
11171               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
11172               if (vtkFaceId >= 0)
11173                 {
11174                   sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId));
11175                   // find also the smds edges on this face
11176                   int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]);
11177                   const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]);
11178                   const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]);
11179                   for (int i = 0; i < nbEdges; i++)
11180                     {
11181                       int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]);
11182                       if (vtkEdgeId >= 0)
11183                         sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId));
11184                     }
11185                 }
11186             }
11187           else if (neighborDim == 2) // skin of the volume
11188             {
11189               DownIdType face(downIds[n], downTypes[n]);
11190               skinFaces[face] = vtkId;
11191               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
11192               if (vtkFaceId >= 0)
11193                 sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId));
11194             }
11195         }
11196     }
11197
11198   // --- identify the edges constituting the wire of each subshape on the skin
11199   //     define polylines with the nodes of edges, equivalent to wires
11200   //     project polylines on subshapes, and partition, to get geom faces
11201
11202   std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
11203   std::set<int> emptySet;
11204   emptySet.clear();
11205   std::set<int> shapeIds;
11206
11207   SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
11208   while (itelem->more())
11209     {
11210       const SMDS_MeshElement *elem = itelem->next();
11211       int shapeId = elem->getshapeId();
11212       int vtkId = elem->getVtkId();
11213       if (!shapeIdToVtkIdSet.count(shapeId))
11214         {
11215           shapeIdToVtkIdSet[shapeId] = emptySet;
11216           shapeIds.insert(shapeId);
11217         }
11218       shapeIdToVtkIdSet[shapeId].insert(vtkId);
11219     }
11220
11221   std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
11222   std::set<DownIdType, DownIdCompare> emptyEdges;
11223   emptyEdges.clear();
11224
11225   std::map<int, std::set<int> >::iterator itShape =  shapeIdToVtkIdSet.begin();
11226   for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
11227     {
11228       int shapeId = itShape->first;
11229       MESSAGE(" --- Shape ID --- "<< shapeId);
11230       shapeIdToEdges[shapeId] = emptyEdges;
11231
11232       std::vector<int> nodesEdges;
11233
11234       std::set<int>::iterator its = itShape->second.begin();
11235       for (; its != itShape->second.end(); ++its)
11236         {
11237           int vtkId = *its;
11238           MESSAGE("     " << vtkId);
11239           int neighborsVtkIds[NBMAXNEIGHBORS];
11240           int downIds[NBMAXNEIGHBORS];
11241           unsigned char downTypes[NBMAXNEIGHBORS];
11242           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11243           for (int n = 0; n < nbNeighbors; n++)
11244             {
11245               if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
11246                 continue;
11247               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
11248               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11249               if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
11250                 {
11251                   DownIdType edge(downIds[n], downTypes[n]);
11252                   if (!shapeIdToEdges[shapeId].count(edge))
11253                     {
11254                       shapeIdToEdges[shapeId].insert(edge);
11255                       int vtkNodeId[3];
11256                       int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId);
11257                       nodesEdges.push_back(vtkNodeId[0]);
11258                       nodesEdges.push_back(vtkNodeId[nbNodes-1]);
11259                       MESSAGE("       --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1);
11260                     }
11261                 }
11262             }
11263         }
11264
11265       std::list<int> order;
11266       order.clear();
11267       if (nodesEdges.size() > 0)
11268         {
11269           order.push_back(nodesEdges[0]); MESSAGE("       --- back " << order.back()+1); // SMDS id = VTK id + 1;
11270           nodesEdges[0] = -1;
11271           order.push_back(nodesEdges[1]); MESSAGE("       --- back " << order.back()+1);
11272           nodesEdges[1] = -1; // do not reuse this edge
11273           bool found = true;
11274           while (found)
11275             {
11276               int nodeTofind = order.back(); // try first to push back
11277               int i = 0;
11278               for (i = 0; i<nodesEdges.size(); i++)
11279                 if (nodesEdges[i] == nodeTofind)
11280                   break;
11281               if (i == nodesEdges.size())
11282                 found = false; // no follower found on back
11283               else
11284                 {
11285                   if (i%2) // odd ==> use the previous one
11286                     if (nodesEdges[i-1] < 0)
11287                       found = false;
11288                     else
11289                       {
11290                         order.push_back(nodesEdges[i-1]); MESSAGE("       --- back " << order.back()+1);
11291                         nodesEdges[i-1] = -1;
11292                       }
11293                   else // even ==> use the next one
11294                     if (nodesEdges[i+1] < 0)
11295                       found = false;
11296                     else
11297                       {
11298                         order.push_back(nodesEdges[i+1]); MESSAGE("       --- back " << order.back()+1);
11299                         nodesEdges[i+1] = -1;
11300                       }
11301                 }
11302               if (found)
11303                 continue;
11304               // try to push front
11305               found = true;
11306               nodeTofind = order.front(); // try to push front
11307               for (i = 0; i<nodesEdges.size(); i++)
11308                 if (nodesEdges[i] == nodeTofind)
11309                   break;
11310               if (i == nodesEdges.size())
11311                 {
11312                   found = false; // no predecessor found on front
11313                   continue;
11314                 }
11315               if (i%2) // odd ==> use the previous one
11316                 if (nodesEdges[i-1] < 0)
11317                   found = false;
11318                 else
11319                   {
11320                     order.push_front(nodesEdges[i-1]); MESSAGE("       --- front " << order.front()+1);
11321                     nodesEdges[i-1] = -1;
11322                   }
11323               else // even ==> use the next one
11324                 if (nodesEdges[i+1] < 0)
11325                   found = false;
11326                 else
11327                   {
11328                     order.push_front(nodesEdges[i+1]); MESSAGE("       --- front " << order.front()+1);
11329                     nodesEdges[i+1] = -1;
11330                   }
11331             }
11332         }
11333
11334
11335       std::vector<int> nodes;
11336       nodes.push_back(shapeId);
11337       std::list<int>::iterator itl = order.begin();
11338       for (; itl != order.end(); itl++)
11339         {
11340           nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
11341           MESSAGE("              ordered node " << nodes[nodes.size()-1]);
11342         }
11343       listOfListOfNodes.push_back(nodes);
11344     }
11345
11346   //     partition geom faces with blocFissure
11347   //     mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose)
11348   //     mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose)
11349
11350   return;
11351 }
11352
11353
11354 //================================================================================
11355 /*!
11356  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11357  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11358  * \return TRUE if operation has been completed successfully, FALSE otherwise
11359  */
11360 //================================================================================
11361
11362 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11363 {
11364   // iterates on volume elements and detect all free faces on them
11365   SMESHDS_Mesh* aMesh = GetMeshDS();
11366   if (!aMesh)
11367     return false;
11368   //bool res = false;
11369   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11370   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11371   while(vIt->more())
11372   {
11373     const SMDS_MeshVolume* volume = vIt->next();
11374     SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
11375     vTool.SetExternalNormal();
11376     //const bool isPoly = volume->IsPoly();
11377     const int iQuad = volume->IsQuadratic();
11378     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11379     {
11380       if (!vTool.IsFreeFace(iface))
11381         continue;
11382       nbFree++;
11383       vector<const SMDS_MeshNode *> nodes;
11384       int nbFaceNodes = vTool.NbFaceNodes(iface);
11385       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11386       int inode = 0;
11387       for ( ; inode < nbFaceNodes; inode += iQuad+1)
11388         nodes.push_back(faceNodes[inode]);
11389       if (iQuad) { // add medium nodes
11390         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11391           nodes.push_back(faceNodes[inode]);
11392         if ( nbFaceNodes == 9 ) // bi-quadratic quad
11393           nodes.push_back(faceNodes[8]);
11394       }
11395       // add new face based on volume nodes
11396       if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
11397         nbExisted++;
11398         continue; // face already exsist
11399       }
11400       AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
11401       nbCreated++;
11402     }
11403   }
11404   return ( nbFree==(nbExisted+nbCreated) );
11405 }
11406
11407 namespace
11408 {
11409   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11410   {
11411     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11412       return n;
11413     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11414   }
11415 }
11416 //================================================================================
11417 /*!
11418  * \brief Creates missing boundary elements
11419  *  \param elements - elements whose boundary is to be checked
11420  *  \param dimension - defines type of boundary elements to create
11421  *  \param group - a group to store created boundary elements in
11422  *  \param targetMesh - a mesh to store created boundary elements in
11423  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11424  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
11425  *                                boundary elements will be copied into the targetMesh
11426  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11427  *                                boundary elements will be added into the new group
11428  *  \param aroundElements - if true, elements will be created on boundary of given
11429  *                          elements else, on boundary of the whole mesh.
11430  * \return nb of added boundary elements
11431  */
11432 //================================================================================
11433
11434 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11435                                        Bnd_Dimension           dimension,
11436                                        SMESH_Group*            group/*=0*/,
11437                                        SMESH_Mesh*             targetMesh/*=0*/,
11438                                        bool                    toCopyElements/*=false*/,
11439                                        bool                    toCopyExistingBoundary/*=false*/,
11440                                        bool                    toAddExistingBondary/*= false*/,
11441                                        bool                    aroundElements/*= false*/)
11442 {
11443   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11444   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11445   // hope that all elements are of the same type, do not check them all
11446   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11447     throw SALOME_Exception(LOCALIZED("wrong element type"));
11448
11449   if ( !targetMesh )
11450     toCopyElements = toCopyExistingBoundary = false;
11451
11452   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11453   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11454   int nbAddedBnd = 0;
11455
11456   // editor adding present bnd elements and optionally holding elements to add to the group
11457   SMESH_MeshEditor* presentEditor;
11458   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11459   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11460
11461   SMESH_MesherHelper helper( *myMesh );
11462   const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
11463   SMDS_VolumeTool vTool;
11464   TIDSortedElemSet avoidSet;
11465   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11466   int inode;
11467
11468   typedef vector<const SMDS_MeshNode*> TConnectivity;
11469
11470   SMDS_ElemIteratorPtr eIt;
11471   if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
11472   else                  eIt = elemSetIterator( elements );
11473
11474   while (eIt->more())
11475   {
11476     const SMDS_MeshElement* elem = eIt->next();
11477     const int              iQuad = elem->IsQuadratic();
11478
11479     // ------------------------------------------------------------------------------------
11480     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11481     // ------------------------------------------------------------------------------------
11482     vector<const SMDS_MeshElement*> presentBndElems;
11483     vector<TConnectivity>           missingBndElems;
11484     TConnectivity nodes, elemNodes;
11485     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
11486     {
11487       vTool.SetExternalNormal();
11488       const SMDS_MeshElement* otherVol = 0;
11489       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11490       {
11491         if ( !vTool.IsFreeFace(iface, &otherVol) &&
11492              ( !aroundElements || elements.count( otherVol )))
11493           continue;
11494         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11495         const int    nbFaceNodes = vTool.NbFaceNodes (iface);
11496         if ( missType == SMDSAbs_Edge ) // boundary edges
11497         {
11498           nodes.resize( 2+iQuad );
11499           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11500           {
11501             for ( int j = 0; j < nodes.size(); ++j )
11502               nodes[j] =nn[i+j];
11503             if ( const SMDS_MeshElement* edge =
11504                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11505               presentBndElems.push_back( edge );
11506             else
11507               missingBndElems.push_back( nodes );
11508           }
11509         }
11510         else // boundary face
11511         {
11512           nodes.clear();
11513           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11514             nodes.push_back( nn[inode] ); // add corner nodes
11515           if (iQuad)
11516             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11517               nodes.push_back( nn[inode] ); // add medium nodes
11518           int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
11519           if ( iCenter > 0 )
11520             nodes.push_back( vTool.GetNodes()[ iCenter ] );
11521
11522           if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
11523                                                                SMDSAbs_Face, /*noMedium=*/false ))
11524             presentBndElems.push_back( f );
11525           else
11526             missingBndElems.push_back( nodes );
11527
11528           if ( targetMesh != myMesh )
11529           {
11530             // add 1D elements on face boundary to be added to a new mesh
11531             const SMDS_MeshElement* edge;
11532             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11533             {
11534               if ( iQuad )
11535                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11536               else
11537                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11538               if ( edge && avoidSet.insert( edge ).second )
11539                 presentBndElems.push_back( edge );
11540             }
11541           }
11542         }
11543       }
11544     }
11545     else if ( elem->GetType() == SMDSAbs_Face ) // elem is a face ------------------------
11546     {
11547       avoidSet.clear(), avoidSet.insert( elem );
11548       elemNodes.assign( SMDS_MeshElement::iterator( elem->interlacedNodesElemIterator() ),
11549                         SMDS_MeshElement::iterator() );
11550       elemNodes.push_back( elemNodes[0] );
11551       nodes.resize( 2 + iQuad );
11552       const int nbLinks = elem->NbCornerNodes();
11553       for ( int i = 0, iN = 0; i < nbLinks; i++, iN += 1+iQuad )
11554       {
11555         nodes[0] = elemNodes[iN];
11556         nodes[1] = elemNodes[iN+1+iQuad];
11557         if ( SMESH_MeshAlgos::FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11558           continue; // not free link
11559
11560         if ( iQuad ) nodes[2] = elemNodes[iN+1];
11561         if ( const SMDS_MeshElement* edge =
11562              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11563           presentBndElems.push_back( edge );
11564         else
11565           missingBndElems.push_back( nodes );
11566       }
11567     }
11568
11569     // ---------------------------------
11570     // 2. Add missing boundary elements
11571     // ---------------------------------
11572     if ( targetMesh != myMesh )
11573       // instead of making a map of nodes in this mesh and targetMesh,
11574       // we create nodes with same IDs.
11575       for ( int i = 0; i < missingBndElems.size(); ++i )
11576       {
11577         TConnectivity& srcNodes = missingBndElems[i];
11578         TConnectivity  nodes( srcNodes.size() );
11579         for ( inode = 0; inode < nodes.size(); ++inode )
11580           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11581         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11582                                                                    missType,
11583                                                                    /*noMedium=*/false))
11584           continue;
11585         tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11586         ++nbAddedBnd;
11587       }
11588     else
11589       for ( int i = 0; i < missingBndElems.size(); ++i )
11590       {
11591         TConnectivity& nodes = missingBndElems[i];
11592         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11593                                                                    missType,
11594                                                                    /*noMedium=*/false))
11595           continue;
11596         SMDS_MeshElement* elem =
11597           tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11598         ++nbAddedBnd;
11599
11600         // try to set a new element to a shape
11601         if ( myMesh->HasShapeToMesh() )
11602         {
11603           bool ok = true;
11604           set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
11605           const int nbN = nodes.size() / (iQuad+1 );
11606           for ( inode = 0; inode < nbN && ok; ++inode )
11607           {
11608             pair<int, TopAbs_ShapeEnum> i_stype =
11609               helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
11610             if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
11611               mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
11612           }
11613           if ( ok && mediumShapes.size() > 1 )
11614           {
11615             set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
11616             pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
11617             for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
11618             {
11619               if (( ok = ( stype_i->first != stype_i_0.first )))
11620                 ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
11621                                         aMesh->IndexToShape( stype_i_0.second ));
11622             }
11623           }
11624           if ( ok && mediumShapes.begin()->first == missShapeType )
11625             aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
11626         }
11627       }
11628
11629     // ----------------------------------
11630     // 3. Copy present boundary elements
11631     // ----------------------------------
11632     if ( toCopyExistingBoundary )
11633       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11634       {
11635         const SMDS_MeshElement* e = presentBndElems[i];
11636         TConnectivity nodes( e->NbNodes() );
11637         for ( inode = 0; inode < nodes.size(); ++inode )
11638           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11639         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11640       }
11641     else // store present elements to add them to a group
11642       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11643       {
11644         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11645       }
11646
11647   } // loop on given elements
11648
11649   // ---------------------------------------------
11650   // 4. Fill group with boundary elements
11651   // ---------------------------------------------
11652   if ( group )
11653   {
11654     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11655       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11656         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11657   }
11658   tgtEditor.myLastCreatedElems.Clear();
11659   tgtEditor2.myLastCreatedElems.Clear();
11660
11661   // -----------------------
11662   // 5. Copy given elements
11663   // -----------------------
11664   if ( toCopyElements && targetMesh != myMesh )
11665   {
11666     if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
11667     else                  eIt = elemSetIterator( elements );
11668     while (eIt->more())
11669     {
11670       const SMDS_MeshElement* elem = eIt->next();
11671       TConnectivity nodes( elem->NbNodes() );
11672       for ( inode = 0; inode < nodes.size(); ++inode )
11673         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11674       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11675
11676       tgtEditor.myLastCreatedElems.Clear();
11677     }
11678   }
11679   return nbAddedBnd;
11680 }