Salome HOME
0022106: EDF 2464 SMESH : Split quadrangles in 4 triangles
[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   SMDS_ElemIteratorPtr elemSetIterator( const TIDSortedElemSet& elements )
109   {
110     typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
111     return SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
112   }
113 }
114
115 //=======================================================================
116 //function : SMESH_MeshEditor
117 //purpose  :
118 //=======================================================================
119
120 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
121   :myMesh( theMesh ) // theMesh may be NULL
122 {
123 }
124
125 //================================================================================
126 /*!
127  * \brief Clears myLastCreatedNodes and myLastCreatedElems
128  */
129 //================================================================================
130
131 void SMESH_MeshEditor::CrearLastCreated()
132 {
133   myLastCreatedNodes.Clear();
134   myLastCreatedElems.Clear();
135 }
136
137
138 //=======================================================================
139 /*!
140  * \brief Add element
141  */
142 //=======================================================================
143
144 SMDS_MeshElement*
145 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
146                              const SMDSAbs_ElementType            type,
147                              const bool                           isPoly,
148                              const int                            ID,
149                              const double                         ballDiameter)
150 {
151   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
152   SMDS_MeshElement* e = 0;
153   int nbnode = node.size();
154   SMESHDS_Mesh* mesh = GetMeshDS();
155   switch ( type ) {
156   case SMDSAbs_Face:
157     if ( !isPoly ) {
158       if      (nbnode == 3) {
159         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
160         else           e = mesh->AddFace      (node[0], node[1], node[2] );
161       }
162       else if (nbnode == 4) {
163         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
164         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
165       }
166       else if (nbnode == 6) {
167         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
168                                                node[4], node[5], ID);
169         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
170                                                node[4], node[5] );
171       }
172       else if (nbnode == 7) {
173         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
174                                                node[4], node[5], node[6], ID);
175         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
176                                                node[4], node[5], node[6] );
177       }
178       else if (nbnode == 8) {
179         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
180                                                node[4], node[5], node[6], node[7], ID);
181         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
182                                                node[4], node[5], node[6], node[7] );
183       }
184       else if (nbnode == 9) {
185         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
186                                                node[4], node[5], node[6], node[7], node[8], ID);
187         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
188                                                node[4], node[5], node[6], node[7], node[8] );
189       }
190     } else {
191       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
192       else           e = mesh->AddPolygonalFace      (node    );
193     }
194     break;
195
196   case SMDSAbs_Volume:
197     if ( !isPoly ) {
198       if      (nbnode == 4) {
199         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
200         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
201       }
202       else if (nbnode == 5) {
203         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
204                                                  node[4], ID);
205         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
206                                                  node[4] );
207       }
208       else if (nbnode == 6) {
209         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
210                                                  node[4], node[5], ID);
211         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
212                                                  node[4], node[5] );
213       }
214       else if (nbnode == 8) {
215         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
216                                                  node[4], node[5], node[6], node[7], ID);
217         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
218                                                  node[4], node[5], node[6], node[7] );
219       }
220       else if (nbnode == 10) {
221         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
222                                                  node[4], node[5], node[6], node[7],
223                                                  node[8], node[9], ID);
224         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
225                                                  node[4], node[5], node[6], node[7],
226                                                  node[8], node[9] );
227       }
228       else if (nbnode == 12) {
229         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
230                                                  node[4], node[5], node[6], node[7],
231                                                  node[8], node[9], node[10], node[11], ID);
232         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
233                                                  node[4], node[5], node[6], node[7],
234                                                  node[8], node[9], node[10], node[11] );
235       }
236       else if (nbnode == 13) {
237         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
238                                                  node[4], node[5], node[6], node[7],
239                                                  node[8], node[9], node[10],node[11],
240                                                  node[12],ID);
241         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
242                                                  node[4], node[5], node[6], node[7],
243                                                  node[8], node[9], node[10],node[11],
244                                                  node[12] );
245       }
246       else if (nbnode == 15) {
247         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
248                                                  node[4], node[5], node[6], node[7],
249                                                  node[8], node[9], node[10],node[11],
250                                                  node[12],node[13],node[14],ID);
251         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
252                                                  node[4], node[5], node[6], node[7],
253                                                  node[8], node[9], node[10],node[11],
254                                                  node[12],node[13],node[14] );
255       }
256       else if (nbnode == 20) {
257         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
258                                                  node[4], node[5], node[6], node[7],
259                                                  node[8], node[9], node[10],node[11],
260                                                  node[12],node[13],node[14],node[15],
261                                                  node[16],node[17],node[18],node[19],ID);
262         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
263                                                  node[4], node[5], node[6], node[7],
264                                                  node[8], node[9], node[10],node[11],
265                                                  node[12],node[13],node[14],node[15],
266                                                  node[16],node[17],node[18],node[19] );
267       }
268       else if (nbnode == 27) {
269         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
270                                                  node[4], node[5], node[6], node[7],
271                                                  node[8], node[9], node[10],node[11],
272                                                  node[12],node[13],node[14],node[15],
273                                                  node[16],node[17],node[18],node[19],
274                                                  node[20],node[21],node[22],node[23],
275                                                  node[24],node[25],node[26], ID);
276         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
277                                                  node[4], node[5], node[6], node[7],
278                                                  node[8], node[9], node[10],node[11],
279                                                  node[12],node[13],node[14],node[15],
280                                                  node[16],node[17],node[18],node[19],
281                                                  node[20],node[21],node[22],node[23],
282                                                  node[24],node[25],node[26] );
283       }
284     }
285     break;
286
287   case SMDSAbs_Edge:
288     if ( nbnode == 2 ) {
289       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
290       else           e = mesh->AddEdge      (node[0], node[1] );
291     }
292     else if ( nbnode == 3 ) {
293       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
294       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
295     }
296     break;
297
298   case SMDSAbs_0DElement:
299     if ( nbnode == 1 ) {
300       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
301       else           e = mesh->Add0DElement      (node[0] );
302     }
303     break;
304
305   case SMDSAbs_Node:
306     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
307     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
308     break;
309
310   case SMDSAbs_Ball:
311     if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], ballDiameter, ID);
312     else           e = mesh->AddBall      (node[0], ballDiameter);
313     break;
314
315   default:;
316   }
317   if ( e ) myLastCreatedElems.Append( e );
318   return e;
319 }
320
321 //=======================================================================
322 /*!
323  * \brief Add element
324  */
325 //=======================================================================
326
327 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
328                                                const SMDSAbs_ElementType type,
329                                                const bool                isPoly,
330                                                const int                 ID)
331 {
332   vector<const SMDS_MeshNode*> nodes;
333   nodes.reserve( nodeIDs.size() );
334   vector<int>::const_iterator id = nodeIDs.begin();
335   while ( id != nodeIDs.end() ) {
336     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
337       nodes.push_back( node );
338     else
339       return 0;
340   }
341   return AddElement( nodes, type, isPoly, ID );
342 }
343
344 //=======================================================================
345 //function : Remove
346 //purpose  : Remove a node or an element.
347 //           Modify a compute state of sub-meshes which become empty
348 //=======================================================================
349
350 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
351                               const bool         isNodes )
352 {
353   myLastCreatedElems.Clear();
354   myLastCreatedNodes.Clear();
355
356   SMESHDS_Mesh* aMesh = GetMeshDS();
357   set< SMESH_subMesh *> smmap;
358
359   int removed = 0;
360   list<int>::const_iterator it = theIDs.begin();
361   for ( ; it != theIDs.end(); it++ ) {
362     const SMDS_MeshElement * elem;
363     if ( isNodes )
364       elem = aMesh->FindNode( *it );
365     else
366       elem = aMesh->FindElement( *it );
367     if ( !elem )
368       continue;
369
370     // Notify VERTEX sub-meshes about modification
371     if ( isNodes ) {
372       const SMDS_MeshNode* node = cast2Node( elem );
373       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
374         if ( int aShapeID = node->getshapeId() )
375           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
376             smmap.insert( sm );
377     }
378     // Find sub-meshes to notify about modification
379     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
380     //     while ( nodeIt->more() ) {
381     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
382     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
383     //       if ( aPosition.get() ) {
384     //         if ( int aShapeID = aPosition->GetShapeId() ) {
385     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
386     //             smmap.insert( sm );
387     //         }
388     //       }
389     //     }
390
391     // Do remove
392     if ( isNodes )
393       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
394     else
395       aMesh->RemoveElement( elem );
396     removed++;
397   }
398
399   // Notify sub-meshes about modification
400   if ( !smmap.empty() ) {
401     set< SMESH_subMesh *>::iterator smIt;
402     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
403       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
404   }
405
406   //   // Check if the whole mesh becomes empty
407   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
408   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
409
410   return removed;
411 }
412
413 //================================================================================
414 /*!
415  * \brief Create 0D elements on all nodes of the given object except those
416  *        nodes on which a 0D element already exists.
417  *  \param elements - Elements on whose nodes to create 0D elements; if empty, 
418  *                    the all mesh is treated
419  *  \param all0DElems - returns all 0D elements found or created on nodes of \a elements
420  */
421 //================================================================================
422
423 void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements,
424                                                    TIDSortedElemSet&       all0DElems )
425 {
426   SMDS_ElemIteratorPtr elemIt;
427   if ( elements.empty() )
428     elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node );
429   else
430     elemIt = elemSetIterator( elements );
431
432   while ( elemIt->more() )
433   {
434     const SMDS_MeshElement* e = elemIt->next();
435     SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
436     while ( nodeIt->more() )
437     {
438       const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
439       SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement );
440       if ( it0D->more() )
441         all0DElems.insert( it0D->next() );
442       else {
443         myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n ));
444         all0DElems.insert( myLastCreatedElems.Last() );
445       }
446     }
447   }
448 }
449
450 //=======================================================================
451 //function : FindShape
452 //purpose  : Return an index of the shape theElem is on
453 //           or zero if a shape not found
454 //=======================================================================
455
456 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
457 {
458   myLastCreatedElems.Clear();
459   myLastCreatedNodes.Clear();
460
461   SMESHDS_Mesh * aMesh = GetMeshDS();
462   if ( aMesh->ShapeToMesh().IsNull() )
463     return 0;
464
465   int aShapeID = theElem->getshapeId();
466   if ( aShapeID < 1 )
467     return 0;
468
469   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
470     if ( sm->Contains( theElem ))
471       return aShapeID;
472
473   if ( theElem->GetType() == SMDSAbs_Node ) {
474     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
475   }
476   else {
477     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
478   }
479
480   TopoDS_Shape aShape; // the shape a node of theElem is on
481   if ( theElem->GetType() != SMDSAbs_Node )
482   {
483     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
484     while ( nodeIt->more() ) {
485       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
486       if ((aShapeID = node->getshapeId()) > 0) {
487         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
488           if ( sm->Contains( theElem ))
489             return aShapeID;
490           if ( aShape.IsNull() )
491             aShape = aMesh->IndexToShape( aShapeID );
492         }
493       }
494     }
495   }
496
497   // None of nodes is on a proper shape,
498   // find the shape among ancestors of aShape on which a node is
499   if ( !aShape.IsNull() ) {
500     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
501     for ( ; ancIt.More(); ancIt.Next() ) {
502       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
503       if ( sm && sm->Contains( theElem ))
504         return aMesh->ShapeToIndex( ancIt.Value() );
505     }
506   }
507   else
508   {
509     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
510     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
511     for ( ; id_sm != id2sm.end(); ++id_sm )
512       if ( id_sm->second->Contains( theElem ))
513         return id_sm->first;
514   }
515
516   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
517   return 0;
518 }
519
520 //=======================================================================
521 //function : IsMedium
522 //purpose  :
523 //=======================================================================
524
525 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
526                                 const SMDSAbs_ElementType typeToCheck)
527 {
528   bool isMedium = false;
529   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
530   while (it->more() && !isMedium ) {
531     const SMDS_MeshElement* elem = it->next();
532     isMedium = elem->IsMediumNode(node);
533   }
534   return isMedium;
535 }
536
537 //=======================================================================
538 //function : shiftNodesQuadTria
539 //purpose  : Shift nodes in the array corresponded to quadratic triangle
540 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
541 //=======================================================================
542
543 static void shiftNodesQuadTria(vector< const SMDS_MeshNode* >& aNodes)
544 {
545   const SMDS_MeshNode* nd1 = aNodes[0];
546   aNodes[0] = aNodes[1];
547   aNodes[1] = aNodes[2];
548   aNodes[2] = nd1;
549   const SMDS_MeshNode* nd2 = aNodes[3];
550   aNodes[3] = aNodes[4];
551   aNodes[4] = aNodes[5];
552   aNodes[5] = nd2;
553 }
554
555 //=======================================================================
556 //function : nbEdgeConnectivity
557 //purpose  : return number of the edges connected with the theNode.
558 //           if theEdges has connections with the other type of the
559 //           elements, return -1
560 //=======================================================================
561
562 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
563 {
564   // SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
565   // int nb=0;
566   // while(elemIt->more()) {
567   //   elemIt->next();
568   //   nb++;
569   // }
570   // return nb;
571   return theNode->NbInverseElements();
572 }
573
574 //=======================================================================
575 //function : getNodesFromTwoTria
576 //purpose  : 
577 //=======================================================================
578
579 static bool getNodesFromTwoTria(const SMDS_MeshElement * theTria1,
580                                 const SMDS_MeshElement * theTria2,
581                                 vector< const SMDS_MeshNode*>& N1,
582                                 vector< const SMDS_MeshNode*>& N2)
583 {
584   N1.assign( theTria1->begin_nodes(), theTria1->end_nodes() );
585   if ( N1.size() < 6 ) return false;
586   N2.assign( theTria2->begin_nodes(), theTria2->end_nodes() );
587   if ( N2.size() < 6 ) return false;
588
589   int sames[3] = {-1,-1,-1};
590   int nbsames = 0;
591   int i, j;
592   for(i=0; i<3; i++) {
593     for(j=0; j<3; j++) {
594       if(N1[i]==N2[j]) {
595         sames[i] = j;
596         nbsames++;
597         break;
598       }
599     }
600   }
601   if(nbsames!=2) return false;
602   if(sames[0]>-1) {
603     shiftNodesQuadTria(N1);
604     if(sames[1]>-1) {
605       shiftNodesQuadTria(N1);
606     }
607   }
608   i = sames[0] + sames[1] + sames[2];
609   for(; i<2; i++) {
610     shiftNodesQuadTria(N2);
611   }
612   // now we receive following N1 and N2 (using numeration as in the image below)
613   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
614   // i.e. first nodes from both arrays form a new diagonal
615   return true;
616 }
617
618 //=======================================================================
619 //function : InverseDiag
620 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
621 //           but having other common link.
622 //           Return False if args are improper
623 //=======================================================================
624
625 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
626                                     const SMDS_MeshElement * theTria2 )
627 {
628   MESSAGE("InverseDiag");
629   myLastCreatedElems.Clear();
630   myLastCreatedNodes.Clear();
631
632   if (!theTria1 || !theTria2)
633     return false;
634
635   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
636   if (!F1) return false;
637   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
638   if (!F2) return false;
639   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
640       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
641
642     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
643     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
644     //    |/ |                                         | \|
645     //  B +--+ 2                                     B +--+ 2
646
647     // put nodes in array and find out indices of the same ones
648     const SMDS_MeshNode* aNodes [6];
649     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
650     int i = 0;
651     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
652     while ( it->more() ) {
653       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
654
655       if ( i > 2 ) // theTria2
656         // find same node of theTria1
657         for ( int j = 0; j < 3; j++ )
658           if ( aNodes[ i ] == aNodes[ j ]) {
659             sameInd[ j ] = i;
660             sameInd[ i ] = j;
661             break;
662           }
663       // next
664       i++;
665       if ( i == 3 ) {
666         if ( it->more() )
667           return false; // theTria1 is not a triangle
668         it = theTria2->nodesIterator();
669       }
670       if ( i == 6 && it->more() )
671         return false; // theTria2 is not a triangle
672     }
673
674     // find indices of 1,2 and of A,B in theTria1
675     int iA = 0, iB = 0, i1 = 0, i2 = 0;
676     for ( i = 0; i < 6; i++ ) {
677       if ( sameInd [ i ] == 0 ) {
678         if ( i < 3 ) i1 = i;
679         else         i2 = i;
680       }
681       else if (i < 3) {
682         if ( iA ) iB = i;
683         else      iA = i;
684       }
685     }
686     // nodes 1 and 2 should not be the same
687     if ( aNodes[ i1 ] == aNodes[ i2 ] )
688       return false;
689
690     // theTria1: A->2
691     aNodes[ iA ] = aNodes[ i2 ];
692     // theTria2: B->1
693     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
694
695     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
696     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
697
698     return true;
699
700   } // end if(F1 && F2)
701
702   // check case of quadratic faces
703   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle &&
704       theTria1->GetEntityType() != SMDSEntity_BiQuad_Triangle)
705     return false;
706   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle&&
707       theTria2->GetEntityType() != SMDSEntity_BiQuad_Triangle)
708     return false;
709
710   //       5
711   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
712   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
713   //    |   / |
714   //  7 +  +  + 6
715   //    | /9  |
716   //    |/    |
717   //  4 +--+--+ 3
718   //       8
719
720   vector< const SMDS_MeshNode* > N1;
721   vector< const SMDS_MeshNode* > N2;
722   if(!getNodesFromTwoTria(theTria1,theTria2,N1,N2))
723     return false;
724   // now we receive following N1 and N2 (using numeration as above image)
725   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
726   // i.e. first nodes from both arrays determ new diagonal
727
728   vector< const SMDS_MeshNode*> N1new( N1.size() );
729   vector< const SMDS_MeshNode*> N2new( N2.size() );
730   N1new.back() = N1.back(); // central node of biquadratic
731   N2new.back() = N2.back();
732   N1new[0] = N1[0];  N2new[0] = N1[0];
733   N1new[1] = N2[0];  N2new[1] = N1[1];
734   N1new[2] = N2[1];  N2new[2] = N2[0];
735   N1new[3] = N1[4];  N2new[3] = N1[3];
736   N1new[4] = N2[3];  N2new[4] = N2[5];
737   N1new[5] = N1[5];  N2new[5] = N1[4];
738   // change nodes in faces
739   GetMeshDS()->ChangeElementNodes( theTria1, &N1new[0], N1new.size() );
740   GetMeshDS()->ChangeElementNodes( theTria2, &N2new[0], N2new.size() );
741
742   // move the central node of biquadratic triangle
743   SMESH_MesherHelper helper( *GetMesh() );
744   for ( int is2nd = 0; is2nd < 2; ++is2nd )
745   {
746     const SMDS_MeshElement*         tria = is2nd ? theTria2 : theTria1;
747     vector< const SMDS_MeshNode*>& nodes = is2nd ? N2new : N1new;
748     if ( nodes.size() < 7 )
749       continue;
750     helper.SetSubShape( tria->getshapeId() );
751     const TopoDS_Face& F = TopoDS::Face( helper.GetSubShape() );
752     gp_Pnt xyz;
753     if ( F.IsNull() )
754     {
755       xyz = ( SMESH_TNodeXYZ( nodes[3] ) +
756               SMESH_TNodeXYZ( nodes[4] ) +
757               SMESH_TNodeXYZ( nodes[5] )) / 3.;
758     }
759     else
760     {
761       bool checkUV;
762       gp_XY uv = ( helper.GetNodeUV( F, nodes[3], nodes[2], &checkUV ) +
763                    helper.GetNodeUV( F, nodes[4], nodes[0], &checkUV ) +
764                    helper.GetNodeUV( F, nodes[5], nodes[1], &checkUV )) / 3.;
765       TopLoc_Location loc;
766       Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc);
767       xyz = S->Value( uv.X(), uv.Y() );
768       xyz.Transform( loc );
769       if ( nodes[6]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE &&  // set UV
770            nodes[6]->getshapeId() > 0 )
771         GetMeshDS()->SetNodeOnFace( nodes[6], nodes[6]->getshapeId(), uv.X(), uv.Y() );
772     }
773     GetMeshDS()->MoveNode( nodes[6], xyz.X(), xyz.Y(), xyz.Z() );
774   }
775   return true;
776 }
777
778 //=======================================================================
779 //function : findTriangles
780 //purpose  : find triangles sharing theNode1-theNode2 link
781 //=======================================================================
782
783 static bool findTriangles(const SMDS_MeshNode *    theNode1,
784                           const SMDS_MeshNode *    theNode2,
785                           const SMDS_MeshElement*& theTria1,
786                           const SMDS_MeshElement*& theTria2)
787 {
788   if ( !theNode1 || !theNode2 ) return false;
789
790   theTria1 = theTria2 = 0;
791
792   set< const SMDS_MeshElement* > emap;
793   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
794   while (it->more()) {
795     const SMDS_MeshElement* elem = it->next();
796     if ( elem->NbCornerNodes() == 3 )
797       emap.insert( elem );
798   }
799   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
800   while (it->more()) {
801     const SMDS_MeshElement* elem = it->next();
802     if ( emap.count( elem )) {
803       if ( !theTria1 )
804       {
805         theTria1 = elem;
806       }
807       else  
808       {
809         theTria2 = elem;
810         // theTria1 must be element with minimum ID
811         if ( theTria2->GetID() < theTria1->GetID() )
812           std::swap( theTria2, theTria1 );
813         return true;
814       }
815     }
816   }
817   return false;
818 }
819
820 //=======================================================================
821 //function : InverseDiag
822 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
823 //           with ones built on the same 4 nodes but having other common link.
824 //           Return false if proper faces not found
825 //=======================================================================
826
827 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
828                                     const SMDS_MeshNode * theNode2)
829 {
830   myLastCreatedElems.Clear();
831   myLastCreatedNodes.Clear();
832
833   MESSAGE( "::InverseDiag()" );
834
835   const SMDS_MeshElement *tr1, *tr2;
836   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
837     return false;
838
839   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
840   if (!F1) return false;
841   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
842   if (!F2) return false;
843   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
844       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
845
846     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
847     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
848     //    |/ |                                    | \|
849     //  B +--+ 2                                B +--+ 2
850
851     // put nodes in array
852     // and find indices of 1,2 and of A in tr1 and of B in tr2
853     int i, iA1 = 0, i1 = 0;
854     const SMDS_MeshNode* aNodes1 [3];
855     SMDS_ElemIteratorPtr it;
856     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
857       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
858       if ( aNodes1[ i ] == theNode1 )
859         iA1 = i; // node A in tr1
860       else if ( aNodes1[ i ] != theNode2 )
861         i1 = i;  // node 1
862     }
863     int iB2 = 0, i2 = 0;
864     const SMDS_MeshNode* aNodes2 [3];
865     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
866       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
867       if ( aNodes2[ i ] == theNode2 )
868         iB2 = i; // node B in tr2
869       else if ( aNodes2[ i ] != theNode1 )
870         i2 = i;  // node 2
871     }
872
873     // nodes 1 and 2 should not be the same
874     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
875       return false;
876
877     // tr1: A->2
878     aNodes1[ iA1 ] = aNodes2[ i2 ];
879     // tr2: B->1
880     aNodes2[ iB2 ] = aNodes1[ i1 ];
881
882     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
883     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
884
885     return true;
886   }
887
888   // check case of quadratic faces
889   return InverseDiag(tr1,tr2);
890 }
891
892 //=======================================================================
893 //function : getQuadrangleNodes
894 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
895 //           fusion of triangles tr1 and tr2 having shared link on
896 //           theNode1 and theNode2
897 //=======================================================================
898
899 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
900                         const SMDS_MeshNode *    theNode1,
901                         const SMDS_MeshNode *    theNode2,
902                         const SMDS_MeshElement * tr1,
903                         const SMDS_MeshElement * tr2 )
904 {
905   if( tr1->NbNodes() != tr2->NbNodes() )
906     return false;
907   // find the 4-th node to insert into tr1
908   const SMDS_MeshNode* n4 = 0;
909   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
910   int i=0;
911   while ( !n4 && i<3 ) {
912     const SMDS_MeshNode * n = cast2Node( it->next() );
913     i++;
914     bool isDiag = ( n == theNode1 || n == theNode2 );
915     if ( !isDiag )
916       n4 = n;
917   }
918   // Make an array of nodes to be in a quadrangle
919   int iNode = 0, iFirstDiag = -1;
920   it = tr1->nodesIterator();
921   i=0;
922   while ( i<3 ) {
923     const SMDS_MeshNode * n = cast2Node( it->next() );
924     i++;
925     bool isDiag = ( n == theNode1 || n == theNode2 );
926     if ( isDiag ) {
927       if ( iFirstDiag < 0 )
928         iFirstDiag = iNode;
929       else if ( iNode - iFirstDiag == 1 )
930         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
931     }
932     else if ( n == n4 ) {
933       return false; // tr1 and tr2 should not have all the same nodes
934     }
935     theQuadNodes[ iNode++ ] = n;
936   }
937   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
938     theQuadNodes[ iNode ] = n4;
939
940   return true;
941 }
942
943 //=======================================================================
944 //function : DeleteDiag
945 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
946 //           with a quadrangle built on the same 4 nodes.
947 //           Return false if proper faces not found
948 //=======================================================================
949
950 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
951                                    const SMDS_MeshNode * theNode2)
952 {
953   myLastCreatedElems.Clear();
954   myLastCreatedNodes.Clear();
955
956   MESSAGE( "::DeleteDiag()" );
957
958   const SMDS_MeshElement *tr1, *tr2;
959   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
960     return false;
961
962   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
963   if (!F1) return false;
964   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
965   if (!F2) return false;
966   SMESHDS_Mesh * aMesh = GetMeshDS();
967
968   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
969       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
970
971     const SMDS_MeshNode* aNodes [ 4 ];
972     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
973       return false;
974
975     const SMDS_MeshElement* newElem = 0;
976     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
977     myLastCreatedElems.Append(newElem);
978     AddToSameGroups( newElem, tr1, aMesh );
979     int aShapeId = tr1->getshapeId();
980     if ( aShapeId )
981       {
982         aMesh->SetMeshElementOnShape( newElem, aShapeId );
983       }
984     aMesh->RemoveElement( tr1 );
985     aMesh->RemoveElement( tr2 );
986
987     return true;
988   }
989
990   // check case of quadratic faces
991   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
992     return false;
993   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
994     return false;
995
996   //       5
997   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
998   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
999   //    |   / |
1000   //  7 +  +  + 6
1001   //    | /9  |
1002   //    |/    |
1003   //  4 +--+--+ 3
1004   //       8
1005
1006   vector< const SMDS_MeshNode* > N1;
1007   vector< const SMDS_MeshNode* > N2;
1008   if(!getNodesFromTwoTria(tr1,tr2,N1,N2))
1009     return false;
1010   // now we receive following N1 and N2 (using numeration as above image)
1011   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
1012   // i.e. first nodes from both arrays determ new diagonal
1013
1014   const SMDS_MeshNode* aNodes[8];
1015   aNodes[0] = N1[0];
1016   aNodes[1] = N1[1];
1017   aNodes[2] = N2[0];
1018   aNodes[3] = N2[1];
1019   aNodes[4] = N1[3];
1020   aNodes[5] = N2[5];
1021   aNodes[6] = N2[3];
1022   aNodes[7] = N1[5];
1023
1024   const SMDS_MeshElement* newElem = 0;
1025   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
1026                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
1027   myLastCreatedElems.Append(newElem);
1028   AddToSameGroups( newElem, tr1, aMesh );
1029   int aShapeId = tr1->getshapeId();
1030   if ( aShapeId )
1031     {
1032       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1033     }
1034   aMesh->RemoveElement( tr1 );
1035   aMesh->RemoveElement( tr2 );
1036
1037   // remove middle node (9)
1038   GetMeshDS()->RemoveNode( N1[4] );
1039
1040   return true;
1041 }
1042
1043 //=======================================================================
1044 //function : Reorient
1045 //purpose  : Reverse theElement orientation
1046 //=======================================================================
1047
1048 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
1049 {
1050   MESSAGE("Reorient");
1051   myLastCreatedElems.Clear();
1052   myLastCreatedNodes.Clear();
1053
1054   if (!theElem)
1055     return false;
1056   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
1057   if ( !it || !it->more() )
1058     return false;
1059
1060   const SMDSAbs_ElementType type = theElem->GetType();
1061   if ( type < SMDSAbs_Edge || type > SMDSAbs_Volume )
1062     return false;
1063
1064   const SMDSAbs_EntityType geomType = theElem->GetEntityType();
1065   if ( geomType == SMDSEntity_Polyhedra ) // polyhedron
1066   {
1067     const SMDS_VtkVolume* aPolyedre =
1068       dynamic_cast<const SMDS_VtkVolume*>( theElem );
1069     if (!aPolyedre) {
1070       MESSAGE("Warning: bad volumic element");
1071       return false;
1072     }
1073     const int nbFaces = aPolyedre->NbFaces();
1074     vector<const SMDS_MeshNode *> poly_nodes;
1075     vector<int> quantities (nbFaces);
1076
1077     // reverse each face of the polyedre
1078     for (int iface = 1; iface <= nbFaces; iface++) {
1079       int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1080       quantities[iface - 1] = nbFaceNodes;
1081
1082       for (inode = nbFaceNodes; inode >= 1; inode--) {
1083         const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1084         poly_nodes.push_back(curNode);
1085       }
1086     }
1087     return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1088   }
1089   else // other elements
1090   {
1091     vector<const SMDS_MeshNode*> nodes( theElem->begin_nodes(), theElem->end_nodes() );
1092     const std::vector<int>& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType );
1093     if ( interlace.empty() )
1094     {
1095       std::reverse( nodes.begin(), nodes.end() ); // polygon
1096     }
1097     else if ( interlace.size() > 1 )
1098     {
1099       SMDS_MeshCell::applyInterlace( interlace, nodes );
1100     }
1101     return GetMeshDS()->ChangeElementNodes( theElem, &nodes[0], nodes.size() );
1102   }
1103   return false;
1104 }
1105
1106 //================================================================================
1107 /*!
1108  * \brief Reorient faces.
1109  * \param theFaces - the faces to reorient. If empty the whole mesh is meant
1110  * \param theDirection - desired direction of normal of \a theFace
1111  * \param theFace - one of \a theFaces that sould be oriented according to
1112  *        \a theDirection and whose orientation defines orientation of other faces
1113  * \return number of reoriented faces.
1114  */
1115 //================================================================================
1116
1117 int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
1118                                   const gp_Dir&            theDirection,
1119                                   const SMDS_MeshElement * theFace)
1120 {
1121   int nbReori = 0;
1122   if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori;
1123
1124   if ( theFaces.empty() )
1125   {
1126     SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true);
1127     while ( fIt->more() )
1128       theFaces.insert( theFaces.end(), fIt->next() );
1129   }
1130
1131   // orient theFace according to theDirection
1132   gp_XYZ normal;
1133   SMESH_MeshAlgos::FaceNormal( theFace, normal, /*normalized=*/false );
1134   if ( normal * theDirection.XYZ() < 0 )
1135     nbReori += Reorient( theFace );
1136
1137   // Orient other faces
1138
1139   set< const SMDS_MeshElement* > startFaces, visitedFaces;
1140   TIDSortedElemSet avoidSet;
1141   set< SMESH_TLink > checkedLinks;
1142   pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
1143
1144   if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
1145     theFaces.erase( theFace );
1146   startFaces.insert( theFace );
1147
1148   int nodeInd1, nodeInd2;
1149   const SMDS_MeshElement*           otherFace;
1150   vector< const SMDS_MeshElement* > facesNearLink;
1151   vector< std::pair< int, int > >   nodeIndsOfFace;
1152
1153   set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
1154   while ( !startFaces.empty() )
1155   {
1156     startFace = startFaces.begin();
1157     theFace = *startFace;
1158     startFaces.erase( startFace );
1159     if ( !visitedFaces.insert( theFace ).second )
1160       continue;
1161
1162     avoidSet.clear();
1163     avoidSet.insert(theFace);
1164
1165     NLink link( theFace->GetNode( 0 ), 0 );
1166
1167     const int nbNodes = theFace->NbCornerNodes();
1168     for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
1169     {
1170       link.second = theFace->GetNode(( i+1 ) % nbNodes );
1171       linkIt_isNew = checkedLinks.insert( link );
1172       if ( !linkIt_isNew.second )
1173       {
1174         // link has already been checked and won't be encountered more
1175         // if the group (theFaces) is manifold
1176         //checkedLinks.erase( linkIt_isNew.first );
1177       }
1178       else
1179       {
1180         facesNearLink.clear();
1181         nodeIndsOfFace.clear();
1182         while (( otherFace = SMESH_MeshAlgos::FindFaceInSet( link.first, link.second,
1183                                                              theFaces, avoidSet,
1184                                                              &nodeInd1, &nodeInd2 )))
1185           if ( otherFace != theFace)
1186           {
1187             facesNearLink.push_back( otherFace );
1188             nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 ));
1189             avoidSet.insert( otherFace );
1190           }
1191         if ( facesNearLink.size() > 1 )
1192         {
1193           // NON-MANIFOLD mesh shell !
1194           // select a face most co-directed with theFace,
1195           // other faces won't be visited this time
1196           gp_XYZ NF, NOF;
1197           SMESH_MeshAlgos::FaceNormal( theFace, NF, /*normalized=*/false );
1198           double proj, maxProj = -1;
1199           for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
1200             SMESH_MeshAlgos::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
1201             if (( proj = Abs( NF * NOF )) > maxProj ) {
1202               maxProj = proj;
1203               otherFace = facesNearLink[i];
1204               nodeInd1  = nodeIndsOfFace[i].first;
1205               nodeInd2  = nodeIndsOfFace[i].second;
1206             }
1207           }
1208           // not to visit rejected faces
1209           for ( size_t i = 0; i < facesNearLink.size(); ++i )
1210             if ( facesNearLink[i] != otherFace && theFaces.size() > 1 )
1211               visitedFaces.insert( facesNearLink[i] );
1212         }
1213         else if ( facesNearLink.size() == 1 )
1214         {
1215           otherFace = facesNearLink[0];
1216           nodeInd1  = nodeIndsOfFace.back().first;
1217           nodeInd2  = nodeIndsOfFace.back().second;
1218         }
1219         if ( otherFace && otherFace != theFace)
1220         {
1221           // link must be reverse in otherFace if orientation ot otherFace
1222           // is same as that of theFace
1223           if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
1224           {
1225             nbReori += Reorient( otherFace );
1226           }
1227           startFaces.insert( otherFace );
1228         }
1229       }
1230       std::swap( link.first, link.second ); // reverse the link
1231     }
1232   }
1233   return nbReori;
1234 }
1235
1236 //=======================================================================
1237 //function : getBadRate
1238 //purpose  :
1239 //=======================================================================
1240
1241 static double getBadRate (const SMDS_MeshElement*               theElem,
1242                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1243 {
1244   SMESH::Controls::TSequenceOfXYZ P;
1245   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1246     return 1e100;
1247   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1248   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1249 }
1250
1251 //=======================================================================
1252 //function : QuadToTri
1253 //purpose  : Cut quadrangles into triangles.
1254 //           theCrit is used to select a diagonal to cut
1255 //=======================================================================
1256
1257 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1258                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1259 {
1260   myLastCreatedElems.Clear();
1261   myLastCreatedNodes.Clear();
1262
1263   if ( !theCrit.get() )
1264     return false;
1265
1266   SMESHDS_Mesh * aMesh = GetMeshDS();
1267
1268   Handle(Geom_Surface) surface;
1269   SMESH_MesherHelper   helper( *GetMesh() );
1270
1271   TIDSortedElemSet::iterator itElem;
1272   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
1273   {
1274     const SMDS_MeshElement* elem = *itElem;
1275     if ( !elem || elem->GetType() != SMDSAbs_Face )
1276       continue;
1277     if ( elem->NbCornerNodes() != 4 )
1278       continue;
1279
1280     // retrieve element nodes
1281     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1282
1283     // compare two sets of possible triangles
1284     double aBadRate1, aBadRate2; // to what extent a set is bad
1285     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1286     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1287     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1288
1289     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1290     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1291     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1292
1293     const int aShapeId = FindShape( elem );
1294     const SMDS_MeshElement* newElem1 = 0;
1295     const SMDS_MeshElement* newElem2 = 0;
1296
1297     if ( !elem->IsQuadratic() ) // split liner quadrangle
1298     {
1299       // for MaxElementLength2D functor we return minimum diagonal for splitting,
1300       // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1301       if ( aBadRate1 <= aBadRate2 ) {
1302         // tr1 + tr2 is better
1303         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1304         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1305       }
1306       else {
1307         // tr3 + tr4 is better
1308         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1309         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1310       }
1311     }
1312     else // split quadratic quadrangle
1313     {
1314       helper.SetIsQuadratic( true );
1315       helper.SetIsBiQuadratic( aNodes.size() == 9 );
1316
1317       helper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem ));
1318       if ( aNodes.size() == 9 )
1319       {
1320         helper.SetIsBiQuadratic( true );
1321         if ( aBadRate1 <= aBadRate2 )
1322           helper.AddTLinkNode( aNodes[0], aNodes[2], aNodes[8] );
1323         else
1324           helper.AddTLinkNode( aNodes[1], aNodes[3], aNodes[8] );
1325       }
1326       // create a new element
1327       if ( aBadRate1 <= aBadRate2 ) {
1328         newElem1 = helper.AddFace( aNodes[2], aNodes[3], aNodes[0] );
1329         newElem2 = helper.AddFace( aNodes[2], aNodes[0], aNodes[1] );
1330       }
1331       else {
1332         newElem1 = helper.AddFace( aNodes[3], aNodes[0], aNodes[1] );
1333         newElem2 = helper.AddFace( aNodes[3], aNodes[1], aNodes[2] );
1334       }
1335     } // quadratic case
1336
1337     // care of a new element
1338
1339     myLastCreatedElems.Append(newElem1);
1340     myLastCreatedElems.Append(newElem2);
1341     AddToSameGroups( newElem1, elem, aMesh );
1342     AddToSameGroups( newElem2, elem, aMesh );
1343
1344     // put a new triangle on the same shape
1345     if ( aShapeId )
1346       aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1347     aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1348
1349     aMesh->RemoveElement( elem );
1350   }
1351   return true;
1352 }
1353
1354 //=======================================================================
1355 /*!
1356  * \brief Split each of given quadrangles into 4 triangles.
1357  * \param theElems - The faces to be splitted. If empty all faces are split.
1358  */
1359 //=======================================================================
1360
1361 void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
1362 {
1363   myLastCreatedElems.Clear();
1364   myLastCreatedNodes.Clear();
1365
1366   SMESH_MesherHelper helper( *GetMesh() );
1367   helper.SetElementsOnShape( true );
1368
1369   SMDS_ElemIteratorPtr faceIt;
1370   if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face);
1371   else                    faceIt = elemSetIterator( theElems );
1372
1373   bool   checkUV;
1374   gp_XY  uv [9]; uv[8] = gp_XY(0,0);
1375   gp_XYZ xyz[9];
1376   vector< const SMDS_MeshNode* > nodes;
1377   SMESHDS_SubMesh*               subMeshDS;
1378   TopoDS_Face                    F;
1379   Handle(Geom_Surface)           surface;
1380   TopLoc_Location                loc;
1381
1382   while ( faceIt->more() )
1383   {
1384     const SMDS_MeshElement* quad = faceIt->next();
1385     if ( !quad || quad->NbCornerNodes() != 4 )
1386       continue;
1387
1388     // get a surface the quad is on
1389
1390     if ( quad->getshapeId() < 1 )
1391     {
1392       F.Nullify();
1393       helper.SetSubShape( 0 );
1394       subMeshDS = 0;
1395     }
1396     else if ( quad->getshapeId() != helper.GetSubShapeID() )
1397     {
1398       helper.SetSubShape( quad->getshapeId() );
1399       if ( !helper.GetSubShape().IsNull() &&
1400            helper.GetSubShape().ShapeType() == TopAbs_FACE )
1401       {
1402         F = TopoDS::Face( helper.GetSubShape() );
1403         surface = BRep_Tool::Surface( F, loc );
1404         subMeshDS = GetMeshDS()->MeshElements( quad->getshapeId() );
1405       }
1406       else
1407       {
1408         helper.SetSubShape( 0 );
1409         subMeshDS = 0;
1410       }
1411     }
1412
1413     // create a central node
1414
1415     const SMDS_MeshNode* nCentral;
1416     nodes.assign( quad->begin_nodes(), quad->end_nodes() );
1417
1418     if ( nodes.size() == 9 )
1419     {
1420       nCentral = nodes.back();
1421     }
1422     else
1423     {
1424       size_t iN = 0;
1425       if ( F.IsNull() )
1426       {
1427         for ( ; iN < nodes.size(); ++iN )
1428           xyz[ iN ] = SMESH_TNodeXYZ( nodes[ iN ] );
1429
1430         for ( ; iN < 8; ++iN ) // mid-side points of a linear qudrangle
1431           xyz[ iN ] = 0.5 * ( xyz[ iN - 4 ] + xyz[( iN - 3 )%4 ] );
1432
1433         xyz[ 8 ] = helper.calcTFI( 0.5, 0.5,
1434                                    xyz[0], xyz[1], xyz[2], xyz[3],
1435                                    xyz[4], xyz[5], xyz[6], xyz[7] );
1436       }
1437       else
1438       {
1439         for ( ; iN < nodes.size(); ++iN )
1440           uv[ iN ] = helper.GetNodeUV( F, nodes[iN], nodes[(iN+2)%4], &checkUV );
1441
1442         for ( ; iN < 8; ++iN ) // UV of mid-side points of a linear qudrangle
1443           uv[ iN ] = helper.GetMiddleUV( surface, uv[ iN - 4 ], uv[( iN - 3 )%4 ] );
1444
1445         uv[ 8 ] = helper.calcTFI( 0.5, 0.5,
1446                                   uv[0], uv[1], uv[2], uv[3],
1447                                   uv[4], uv[5], uv[6], uv[7] );
1448
1449         gp_Pnt p = surface->Value( uv[8].X(), uv[8].Y() ).Transformed( loc );
1450         xyz[ 8 ] = p.XYZ();
1451       }
1452
1453       nCentral = helper.AddNode( xyz[8].X(), xyz[8].Y(), xyz[8].Z(), /*id=*/0,
1454                                  uv[8].X(), uv[8].Y() );
1455       myLastCreatedNodes.Append( nCentral );
1456     }
1457
1458     // create 4 triangles
1459
1460     GetMeshDS()->RemoveFreeElement( quad, subMeshDS, /*fromGroups=*/false );
1461     
1462     helper.SetIsQuadratic  ( nodes.size() > 4 );
1463     helper.SetIsBiQuadratic( nodes.size() == 9 );
1464     if ( helper.GetIsQuadratic() )
1465       helper.AddTLinks( static_cast< const SMDS_MeshFace*>( quad ));
1466
1467     for ( int i = 0; i < 4; ++i )
1468     {
1469       SMDS_MeshElement* tria = helper.AddFace( nodes[ i ],
1470                                                nodes[(i+1)%4],
1471                                                nCentral );
1472       ReplaceElemInGroups( tria, quad, GetMeshDS() );
1473       myLastCreatedElems.Append( tria );
1474     }
1475   }
1476 }
1477
1478 //=======================================================================
1479 //function : BestSplit
1480 //purpose  : Find better diagonal for cutting.
1481 //=======================================================================
1482
1483 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1484                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1485 {
1486   myLastCreatedElems.Clear();
1487   myLastCreatedNodes.Clear();
1488
1489   if (!theCrit.get())
1490     return -1;
1491
1492   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1493     return -1;
1494
1495   if( theQuad->NbNodes()==4 ||
1496       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1497
1498     // retrieve element nodes
1499     const SMDS_MeshNode* aNodes [4];
1500     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1501     int i = 0;
1502     //while (itN->more())
1503     while (i<4) {
1504       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1505     }
1506     // compare two sets of possible triangles
1507     double aBadRate1, aBadRate2; // to what extent a set is bad
1508     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1509     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1510     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1511
1512     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1513     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1514     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1515     // for MaxElementLength2D functor we return minimum diagonal for splitting,
1516     // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1517     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1518       return 1; // diagonal 1-3
1519
1520     return 2; // diagonal 2-4
1521   }
1522   return -1;
1523 }
1524
1525 namespace
1526 {
1527   // Methods of splitting volumes into tetra
1528
1529   const int theHexTo5_1[5*4+1] =
1530     {
1531       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1532     };
1533   const int theHexTo5_2[5*4+1] =
1534     {
1535       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1536     };
1537   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1538
1539   const int theHexTo6_1[6*4+1] =
1540     {
1541       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
1542     };
1543   const int theHexTo6_2[6*4+1] =
1544     {
1545       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
1546     };
1547   const int theHexTo6_3[6*4+1] =
1548     {
1549       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
1550     };
1551   const int theHexTo6_4[6*4+1] =
1552     {
1553       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
1554     };
1555   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1556
1557   const int thePyraTo2_1[2*4+1] =
1558     {
1559       0, 1, 2, 4,    0, 2, 3, 4,   -1
1560     };
1561   const int thePyraTo2_2[2*4+1] =
1562     {
1563       1, 2, 3, 4,    1, 3, 0, 4,   -1
1564     };
1565   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1566
1567   const int thePentaTo3_1[3*4+1] =
1568     {
1569       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1570     };
1571   const int thePentaTo3_2[3*4+1] =
1572     {
1573       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1574     };
1575   const int thePentaTo3_3[3*4+1] =
1576     {
1577       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1578     };
1579   const int thePentaTo3_4[3*4+1] =
1580     {
1581       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1582     };
1583   const int thePentaTo3_5[3*4+1] =
1584     {
1585       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1586     };
1587   const int thePentaTo3_6[3*4+1] =
1588     {
1589       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1590     };
1591   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1592                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1593
1594   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1595   {
1596     int _n1, _n2, _n3;
1597     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1598     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1599     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1600   };
1601   struct TSplitMethod
1602   {
1603     int        _nbTetra;
1604     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1605     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1606     bool       _ownConn;      //!< to delete _connectivity in destructor
1607     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1608
1609     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1610       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1611     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1612     bool hasFacet( const TTriangleFacet& facet ) const
1613     {
1614       const int* tetConn = _connectivity;
1615       for ( ; tetConn[0] >= 0; tetConn += 4 )
1616         if (( facet.contains( tetConn[0] ) +
1617               facet.contains( tetConn[1] ) +
1618               facet.contains( tetConn[2] ) +
1619               facet.contains( tetConn[3] )) == 3 )
1620           return true;
1621       return false;
1622     }
1623   };
1624
1625   //=======================================================================
1626   /*!
1627    * \brief return TSplitMethod for the given element
1628    */
1629   //=======================================================================
1630
1631   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1632   {
1633     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1634
1635     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1636     // an edge and a face barycenter; tertaherdons are based on triangles and
1637     // a volume barycenter
1638     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1639
1640     // Find out how adjacent volumes are split
1641
1642     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1643     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1644     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1645     {
1646       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1647       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1648       if ( nbNodes < 4 ) continue;
1649
1650       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1651       const int* nInd = vol.GetFaceNodesIndices( iF );
1652       if ( nbNodes == 4 )
1653       {
1654         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1655         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1656         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1657         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1658       }
1659       else
1660       {
1661         int iCom = 0; // common node of triangle faces to split into
1662         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1663         {
1664           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1665                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1666                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1667           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1668                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1669                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1670           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1671           {
1672             triaSplits.push_back( t012 );
1673             triaSplits.push_back( t023 );
1674             break;
1675           }
1676         }
1677       }
1678       if ( !triaSplits.empty() )
1679         hasAdjacentSplits = true;
1680     }
1681
1682     // Among variants of split method select one compliant with adjacent volumes
1683
1684     TSplitMethod method;
1685     if ( !vol.Element()->IsPoly() && !is24TetMode )
1686     {
1687       int nbVariants = 2, nbTet = 0;
1688       const int** connVariants = 0;
1689       switch ( vol.Element()->GetEntityType() )
1690       {
1691       case SMDSEntity_Hexa:
1692       case SMDSEntity_Quad_Hexa:
1693       case SMDSEntity_TriQuad_Hexa:
1694         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1695           connVariants = theHexTo5, nbTet = 5;
1696         else
1697           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1698         break;
1699       case SMDSEntity_Pyramid:
1700       case SMDSEntity_Quad_Pyramid:
1701         connVariants = thePyraTo2;  nbTet = 2;
1702         break;
1703       case SMDSEntity_Penta:
1704       case SMDSEntity_Quad_Penta:
1705         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1706         break;
1707       default:
1708         nbVariants = 0;
1709       }
1710       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1711       {
1712         // check method compliancy with adjacent tetras,
1713         // all found splits must be among facets of tetras described by this method
1714         method = TSplitMethod( nbTet, connVariants[variant] );
1715         if ( hasAdjacentSplits && method._nbTetra > 0 )
1716         {
1717           bool facetCreated = true;
1718           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1719           {
1720             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1721             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1722               facetCreated = method.hasFacet( *facet );
1723           }
1724           if ( !facetCreated )
1725             method = TSplitMethod(0); // incompatible method
1726         }
1727       }
1728     }
1729     if ( method._nbTetra < 1 )
1730     {
1731       // No standard method is applicable, use a generic solution:
1732       // each facet of a volume is split into triangles and
1733       // each of triangles and a volume barycenter form a tetrahedron.
1734
1735       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1736
1737       int* connectivity = new int[ maxTetConnSize + 1 ];
1738       method._connectivity = connectivity;
1739       method._ownConn = true;
1740       method._baryNode = !isHex27; // to create central node or not
1741
1742       int connSize = 0;
1743       int baryCenInd = vol.NbNodes() - int( isHex27 );
1744       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1745       {
1746         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1747         const int*   nInd = vol.GetFaceNodesIndices( iF );
1748         // find common node of triangle facets of tetra to create
1749         int iCommon = 0; // index in linear numeration
1750         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1751         if ( !triaSplits.empty() )
1752         {
1753           // by found facets
1754           const TTriangleFacet* facet = &triaSplits.front();
1755           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1756             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1757                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1758               break;
1759         }
1760         else if ( nbNodes > 3 && !is24TetMode )
1761         {
1762           // find the best method of splitting into triangles by aspect ratio
1763           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1764           map< double, int > badness2iCommon;
1765           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1766           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1767           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1768           {
1769             double badness = 0;
1770             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1771             {
1772               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1773                                       nodes[ iQ*((iLast-1)%nbNodes)],
1774                                       nodes[ iQ*((iLast  )%nbNodes)]);
1775               badness += getBadRate( &tria, aspectRatio );
1776             }
1777             badness2iCommon.insert( make_pair( badness, iCommon ));
1778           }
1779           // use iCommon with lowest badness
1780           iCommon = badness2iCommon.begin()->second;
1781         }
1782         if ( iCommon >= nbNodes )
1783           iCommon = 0; // something wrong
1784
1785         // fill connectivity of tetrahedra based on a current face
1786         int nbTet = nbNodes - 2;
1787         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1788         {
1789           int faceBaryCenInd;
1790           if ( isHex27 )
1791           {
1792             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
1793             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
1794           }
1795           else
1796           {
1797             method._faceBaryNode[ iF ] = 0;
1798             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1799           }
1800           nbTet = nbNodes;
1801           for ( int i = 0; i < nbTet; ++i )
1802           {
1803             int i1 = i, i2 = (i+1) % nbNodes;
1804             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1805             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1806             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1807             connectivity[ connSize++ ] = faceBaryCenInd;
1808             connectivity[ connSize++ ] = baryCenInd;
1809           }
1810         }
1811         else
1812         {
1813           for ( int i = 0; i < nbTet; ++i )
1814           {
1815             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1816             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1817             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1818             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1819             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1820             connectivity[ connSize++ ] = baryCenInd;
1821           }
1822         }
1823         method._nbTetra += nbTet;
1824
1825       } // loop on volume faces
1826
1827       connectivity[ connSize++ ] = -1;
1828
1829     } // end of generic solution
1830
1831     return method;
1832   }
1833   //================================================================================
1834   /*!
1835    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1836    */
1837   //================================================================================
1838
1839   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1840   {
1841     // find the tetrahedron including the three nodes of facet
1842     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1843     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1844     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1845     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1846     while ( volIt1->more() )
1847     {
1848       const SMDS_MeshElement* v = volIt1->next();
1849       SMDSAbs_EntityType type = v->GetEntityType();
1850       if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
1851         continue;
1852       if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
1853         continue; // medium node not allowed
1854       const int ind2 = v->GetNodeIndex( n2 );
1855       if ( ind2 < 0 || 3 < ind2 )
1856         continue;
1857       const int ind3 = v->GetNodeIndex( n3 );
1858       if ( ind3 < 0 || 3 < ind3 )
1859         continue;
1860       return true;
1861     }
1862     return false;
1863   }
1864
1865   //=======================================================================
1866   /*!
1867    * \brief A key of a face of volume
1868    */
1869   //=======================================================================
1870
1871   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
1872   {
1873     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1874     {
1875       TIDSortedNodeSet sortedNodes;
1876       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1877       int nbNodes = vol.NbFaceNodes( iF );
1878       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1879       for ( int i = 0; i < nbNodes; i += iQ )
1880         sortedNodes.insert( fNodes[i] );
1881       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1882       first.first   = (*(n++))->GetID();
1883       first.second  = (*(n++))->GetID();
1884       second.first  = (*(n++))->GetID();
1885       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
1886     }
1887   };
1888 } // namespace
1889
1890 //=======================================================================
1891 //function : SplitVolumesIntoTetra
1892 //purpose  : Split volume elements into tetrahedra.
1893 //=======================================================================
1894
1895 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1896                                               const int                theMethodFlags)
1897 {
1898   // std-like iterator on coordinates of nodes of mesh element
1899   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1900   NXyzIterator xyzEnd;
1901
1902   SMDS_VolumeTool    volTool;
1903   SMESH_MesherHelper helper( *GetMesh());
1904
1905   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1906   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1907
1908   SMESH_SequenceOfElemPtr newNodes, newElems;
1909
1910   // map face of volume to it's baricenrtic node
1911   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1912   double bc[3];
1913
1914   TIDSortedElemSet::const_iterator elem = theElems.begin();
1915   for ( ; elem != theElems.end(); ++elem )
1916   {
1917     if ( (*elem)->GetType() != SMDSAbs_Volume )
1918       continue;
1919     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1920     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
1921       continue;
1922
1923     if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
1924
1925     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1926     if ( splitMethod._nbTetra < 1 ) continue;
1927
1928     // find submesh to add new tetras to
1929     if ( !subMesh || !subMesh->Contains( *elem ))
1930     {
1931       int shapeID = FindShape( *elem );
1932       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1933       subMesh = GetMeshDS()->MeshElements( shapeID );
1934     }
1935     int iQ;
1936     if ( (*elem)->IsQuadratic() )
1937     {
1938       iQ = 2;
1939       // add quadratic links to the helper
1940       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1941       {
1942         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1943         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
1944         for ( int iN = 0; iN < nbN; iN += iQ )
1945           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
1946       }
1947       helper.SetIsQuadratic( true );
1948     }
1949     else
1950     {
1951       iQ = 1;
1952       helper.SetIsQuadratic( false );
1953     }
1954     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1955     helper.SetElementsOnShape( true );
1956     if ( splitMethod._baryNode )
1957     {
1958       // make a node at barycenter
1959       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1960       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1961       nodes.push_back( gcNode );
1962       newNodes.Append( gcNode );
1963     }
1964     if ( !splitMethod._faceBaryNode.empty() )
1965     {
1966       // make or find baricentric nodes of faces
1967       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1968       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1969       {
1970         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1971           volFace2BaryNode.insert
1972           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
1973         if ( !f_n->second )
1974         {
1975           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1976           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1977         }
1978         nodes.push_back( iF_n->second = f_n->second );
1979       }
1980     }
1981
1982     // make tetras
1983     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1984     const int* tetConn = splitMethod._connectivity;
1985     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1986       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1987                                                        nodes[ tetConn[1] ],
1988                                                        nodes[ tetConn[2] ],
1989                                                        nodes[ tetConn[3] ]));
1990
1991     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1992
1993     // Split faces on sides of the split volume
1994
1995     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1996     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1997     {
1998       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1999       if ( nbNodes < 4 ) continue;
2000
2001       // find an existing face
2002       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
2003                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
2004       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
2005                                                                        /*noMedium=*/false))
2006       {
2007         // make triangles
2008         helper.SetElementsOnShape( false );
2009         vector< const SMDS_MeshElement* > triangles;
2010
2011         // find submesh to add new triangles in
2012         if ( !fSubMesh || !fSubMesh->Contains( face ))
2013         {
2014           int shapeID = FindShape( face );
2015           fSubMesh = GetMeshDS()->MeshElements( shapeID );
2016         }
2017         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
2018         if ( iF_n != splitMethod._faceBaryNode.end() )
2019         {
2020           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
2021           {
2022             const SMDS_MeshNode* n1 = fNodes[iN];
2023             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
2024             const SMDS_MeshNode *n3 = iF_n->second;
2025             if ( !volTool.IsFaceExternal( iF ))
2026               swap( n2, n3 );
2027             triangles.push_back( helper.AddFace( n1,n2,n3 ));
2028
2029             if ( fSubMesh && n3->getshapeId() < 1 )
2030               fSubMesh->AddNode( n3 );
2031           }
2032         }
2033         else
2034         {
2035           // among possible triangles create ones discribed by split method
2036           const int* nInd = volTool.GetFaceNodesIndices( iF );
2037           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
2038           int iCom = 0; // common node of triangle faces to split into
2039           list< TTriangleFacet > facets;
2040           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
2041           {
2042             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
2043                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
2044                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
2045             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
2046                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
2047                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
2048             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
2049             {
2050               facets.push_back( t012 );
2051               facets.push_back( t023 );
2052               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
2053                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
2054                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
2055                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
2056               break;
2057             }
2058           }
2059           list< TTriangleFacet >::iterator facet = facets.begin();
2060           for ( ; facet != facets.end(); ++facet )
2061           {
2062             if ( !volTool.IsFaceExternal( iF ))
2063               swap( facet->_n2, facet->_n3 );
2064             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
2065                                                  volNodes[ facet->_n2 ],
2066                                                  volNodes[ facet->_n3 ]));
2067           }
2068         }
2069         for ( int i = 0; i < triangles.size(); ++i )
2070         {
2071           if ( !triangles[i] ) continue;
2072           if ( fSubMesh )
2073             fSubMesh->AddElement( triangles[i]);
2074           newElems.Append( triangles[i] );
2075         }
2076         ReplaceElemInGroups( face, triangles, GetMeshDS() );
2077         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
2078       }
2079
2080     } // loop on volume faces to split them into triangles
2081
2082     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
2083
2084     if ( geomType == SMDSEntity_TriQuad_Hexa )
2085     {
2086       // remove medium nodes that could become free
2087       for ( int i = 20; i < volTool.NbNodes(); ++i )
2088         if ( volNodes[i]->NbInverseElements() == 0 )
2089           GetMeshDS()->RemoveNode( volNodes[i] );
2090     }
2091   } // loop on volumes to split
2092
2093   myLastCreatedNodes = newNodes;
2094   myLastCreatedElems = newElems;
2095 }
2096
2097 //=======================================================================
2098 //function : AddToSameGroups
2099 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
2100 //=======================================================================
2101
2102 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
2103                                         const SMDS_MeshElement* elemInGroups,
2104                                         SMESHDS_Mesh *          aMesh)
2105 {
2106   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2107   if (!groups.empty()) {
2108     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2109     for ( ; grIt != groups.end(); grIt++ ) {
2110       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2111       if ( group && group->Contains( elemInGroups ))
2112         group->SMDSGroup().Add( elemToAdd );
2113     }
2114   }
2115 }
2116
2117
2118 //=======================================================================
2119 //function : RemoveElemFromGroups
2120 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
2121 //=======================================================================
2122 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
2123                                              SMESHDS_Mesh *          aMesh)
2124 {
2125   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2126   if (!groups.empty())
2127   {
2128     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
2129     for (; GrIt != groups.end(); GrIt++)
2130     {
2131       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
2132       if (!grp || grp->IsEmpty()) continue;
2133       grp->SMDSGroup().Remove(removeelem);
2134     }
2135   }
2136 }
2137
2138 //================================================================================
2139 /*!
2140  * \brief Replace elemToRm by elemToAdd in the all groups
2141  */
2142 //================================================================================
2143
2144 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
2145                                             const SMDS_MeshElement* elemToAdd,
2146                                             SMESHDS_Mesh *          aMesh)
2147 {
2148   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2149   if (!groups.empty()) {
2150     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2151     for ( ; grIt != groups.end(); grIt++ ) {
2152       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2153       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
2154         group->SMDSGroup().Add( elemToAdd );
2155     }
2156   }
2157 }
2158
2159 //================================================================================
2160 /*!
2161  * \brief Replace elemToRm by elemToAdd in the all groups
2162  */
2163 //================================================================================
2164
2165 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
2166                                             const vector<const SMDS_MeshElement*>& elemToAdd,
2167                                             SMESHDS_Mesh *                         aMesh)
2168 {
2169   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2170   if (!groups.empty())
2171   {
2172     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2173     for ( ; grIt != groups.end(); grIt++ ) {
2174       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2175       if ( group && group->SMDSGroup().Remove( elemToRm ) )
2176         for ( int i = 0; i < elemToAdd.size(); ++i )
2177           group->SMDSGroup().Add( elemToAdd[ i ] );
2178     }
2179   }
2180 }
2181
2182 //=======================================================================
2183 //function : QuadToTri
2184 //purpose  : Cut quadrangles into triangles.
2185 //           theCrit is used to select a diagonal to cut
2186 //=======================================================================
2187
2188 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
2189                                   const bool         the13Diag)
2190 {
2191   myLastCreatedElems.Clear();
2192   myLastCreatedNodes.Clear();
2193
2194   MESSAGE( "::QuadToTri()" );
2195
2196   SMESHDS_Mesh * aMesh = GetMeshDS();
2197
2198   Handle(Geom_Surface) surface;
2199   SMESH_MesherHelper   helper( *GetMesh() );
2200
2201   TIDSortedElemSet::iterator itElem;
2202   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2203     const SMDS_MeshElement* elem = *itElem;
2204     if ( !elem || elem->GetType() != SMDSAbs_Face )
2205       continue;
2206     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
2207     if(!isquad) continue;
2208
2209     if(elem->NbNodes()==4) {
2210       // retrieve element nodes
2211       const SMDS_MeshNode* aNodes [4];
2212       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2213       int i = 0;
2214       while ( itN->more() )
2215         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2216
2217       int aShapeId = FindShape( elem );
2218       const SMDS_MeshElement* newElem1 = 0;
2219       const SMDS_MeshElement* newElem2 = 0;
2220       if ( the13Diag ) {
2221         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
2222         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
2223       }
2224       else {
2225         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
2226         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
2227       }
2228       myLastCreatedElems.Append(newElem1);
2229       myLastCreatedElems.Append(newElem2);
2230       // put a new triangle on the same shape and add to the same groups
2231       if ( aShapeId )
2232         {
2233           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2234           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2235         }
2236       AddToSameGroups( newElem1, elem, aMesh );
2237       AddToSameGroups( newElem2, elem, aMesh );
2238       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
2239       aMesh->RemoveElement( elem );
2240     }
2241
2242     // Quadratic quadrangle
2243
2244     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
2245
2246       // get surface elem is on
2247       int aShapeId = FindShape( elem );
2248       if ( aShapeId != helper.GetSubShapeID() ) {
2249         surface.Nullify();
2250         TopoDS_Shape shape;
2251         if ( aShapeId > 0 )
2252           shape = aMesh->IndexToShape( aShapeId );
2253         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
2254           TopoDS_Face face = TopoDS::Face( shape );
2255           surface = BRep_Tool::Surface( face );
2256           if ( !surface.IsNull() )
2257             helper.SetSubShape( shape );
2258         }
2259       }
2260
2261       const SMDS_MeshNode* aNodes [8];
2262       const SMDS_MeshNode* inFaceNode = 0;
2263       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2264       int i = 0;
2265       while ( itN->more() ) {
2266         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2267         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
2268              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
2269         {
2270           inFaceNode = aNodes[ i-1 ];
2271         }
2272       }
2273
2274       // find middle point for (0,1,2,3)
2275       // and create a node in this point;
2276       gp_XYZ p( 0,0,0 );
2277       if ( surface.IsNull() ) {
2278         for(i=0; i<4; i++)
2279           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
2280         p /= 4;
2281       }
2282       else {
2283         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
2284         gp_XY uv( 0,0 );
2285         for(i=0; i<4; i++)
2286           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
2287         uv /= 4.;
2288         p = surface->Value( uv.X(), uv.Y() ).XYZ();
2289       }
2290       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
2291       myLastCreatedNodes.Append(newN);
2292
2293       // create a new element
2294       const SMDS_MeshElement* newElem1 = 0;
2295       const SMDS_MeshElement* newElem2 = 0;
2296       if ( the13Diag ) {
2297         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
2298                                   aNodes[6], aNodes[7], newN );
2299         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
2300                                   newN,      aNodes[4], aNodes[5] );
2301       }
2302       else {
2303         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
2304                                   aNodes[7], aNodes[4], newN );
2305         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
2306                                   newN,      aNodes[5], aNodes[6] );
2307       }
2308       myLastCreatedElems.Append(newElem1);
2309       myLastCreatedElems.Append(newElem2);
2310       // put a new triangle on the same shape and add to the same groups
2311       if ( aShapeId )
2312         {
2313           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2314           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2315         }
2316       AddToSameGroups( newElem1, elem, aMesh );
2317       AddToSameGroups( newElem2, elem, aMesh );
2318       aMesh->RemoveElement( elem );
2319     }
2320   }
2321
2322   return true;
2323 }
2324
2325 //=======================================================================
2326 //function : getAngle
2327 //purpose  :
2328 //=======================================================================
2329
2330 double getAngle(const SMDS_MeshElement * tr1,
2331                 const SMDS_MeshElement * tr2,
2332                 const SMDS_MeshNode *    n1,
2333                 const SMDS_MeshNode *    n2)
2334 {
2335   double angle = 2. * M_PI; // bad angle
2336
2337   // get normals
2338   SMESH::Controls::TSequenceOfXYZ P1, P2;
2339   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2340        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2341     return angle;
2342   gp_Vec N1,N2;
2343   if(!tr1->IsQuadratic())
2344     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2345   else
2346     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2347   if ( N1.SquareMagnitude() <= gp::Resolution() )
2348     return angle;
2349   if(!tr2->IsQuadratic())
2350     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2351   else
2352     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2353   if ( N2.SquareMagnitude() <= gp::Resolution() )
2354     return angle;
2355
2356   // find the first diagonal node n1 in the triangles:
2357   // take in account a diagonal link orientation
2358   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2359   for ( int t = 0; t < 2; t++ ) {
2360     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2361     int i = 0, iDiag = -1;
2362     while ( it->more()) {
2363       const SMDS_MeshElement *n = it->next();
2364       if ( n == n1 || n == n2 ) {
2365         if ( iDiag < 0)
2366           iDiag = i;
2367         else {
2368           if ( i - iDiag == 1 )
2369             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2370           else
2371             nFirst[ t ] = n;
2372           break;
2373         }
2374       }
2375       i++;
2376     }
2377   }
2378   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2379     N2.Reverse();
2380
2381   angle = N1.Angle( N2 );
2382   //SCRUTE( angle );
2383   return angle;
2384 }
2385
2386 // =================================================
2387 // class generating a unique ID for a pair of nodes
2388 // and able to return nodes by that ID
2389 // =================================================
2390 class LinkID_Gen {
2391 public:
2392
2393   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2394     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2395   {}
2396
2397   long GetLinkID (const SMDS_MeshNode * n1,
2398                   const SMDS_MeshNode * n2) const
2399   {
2400     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2401   }
2402
2403   bool GetNodes (const long             theLinkID,
2404                  const SMDS_MeshNode* & theNode1,
2405                  const SMDS_MeshNode* & theNode2) const
2406   {
2407     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2408     if ( !theNode1 ) return false;
2409     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2410     if ( !theNode2 ) return false;
2411     return true;
2412   }
2413
2414 private:
2415   LinkID_Gen();
2416   const SMESHDS_Mesh* myMesh;
2417   long                myMaxID;
2418 };
2419
2420
2421 //=======================================================================
2422 //function : TriToQuad
2423 //purpose  : Fuse neighbour triangles into quadrangles.
2424 //           theCrit is used to select a neighbour to fuse with.
2425 //           theMaxAngle is a max angle between element normals at which
2426 //           fusion is still performed.
2427 //=======================================================================
2428
2429 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2430                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2431                                   const double                         theMaxAngle)
2432 {
2433   myLastCreatedElems.Clear();
2434   myLastCreatedNodes.Clear();
2435
2436   MESSAGE( "::TriToQuad()" );
2437
2438   if ( !theCrit.get() )
2439     return false;
2440
2441   SMESHDS_Mesh * aMesh = GetMeshDS();
2442
2443   // Prepare data for algo: build
2444   // 1. map of elements with their linkIDs
2445   // 2. map of linkIDs with their elements
2446
2447   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2448   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2449   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2450   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2451
2452   TIDSortedElemSet::iterator itElem;
2453   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
2454   {
2455     const SMDS_MeshElement* elem = *itElem;
2456     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2457     bool IsTria = ( elem->NbCornerNodes()==3 );
2458     if (!IsTria) continue;
2459
2460     // retrieve element nodes
2461     const SMDS_MeshNode* aNodes [4];
2462     SMDS_NodeIteratorPtr itN = elem->nodeIterator();
2463     int i = 0;
2464     while ( i < 3 )
2465       aNodes[ i++ ] = itN->next();
2466     aNodes[ 3 ] = aNodes[ 0 ];
2467
2468     // fill maps
2469     for ( i = 0; i < 3; i++ ) {
2470       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2471       // check if elements sharing a link can be fused
2472       itLE = mapLi_listEl.find( link );
2473       if ( itLE != mapLi_listEl.end() ) {
2474         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2475           continue;
2476         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2477         //if ( FindShape( elem ) != FindShape( elem2 ))
2478         //  continue; // do not fuse triangles laying on different shapes
2479         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2480           continue; // avoid making badly shaped quads
2481         (*itLE).second.push_back( elem );
2482       }
2483       else {
2484         mapLi_listEl[ link ].push_back( elem );
2485       }
2486       mapEl_setLi [ elem ].insert( link );
2487     }
2488   }
2489   // Clean the maps from the links shared by a sole element, ie
2490   // links to which only one element is bound in mapLi_listEl
2491
2492   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2493     int nbElems = (*itLE).second.size();
2494     if ( nbElems < 2  ) {
2495       const SMDS_MeshElement* elem = (*itLE).second.front();
2496       SMESH_TLink link = (*itLE).first;
2497       mapEl_setLi[ elem ].erase( link );
2498       if ( mapEl_setLi[ elem ].empty() )
2499         mapEl_setLi.erase( elem );
2500     }
2501   }
2502
2503   // Algo: fuse triangles into quadrangles
2504
2505   while ( ! mapEl_setLi.empty() ) {
2506     // Look for the start element:
2507     // the element having the least nb of shared links
2508     const SMDS_MeshElement* startElem = 0;
2509     int minNbLinks = 4;
2510     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2511       int nbLinks = (*itEL).second.size();
2512       if ( nbLinks < minNbLinks ) {
2513         startElem = (*itEL).first;
2514         minNbLinks = nbLinks;
2515         if ( minNbLinks == 1 )
2516           break;
2517       }
2518     }
2519
2520     // search elements to fuse starting from startElem or links of elements
2521     // fused earlyer - startLinks
2522     list< SMESH_TLink > startLinks;
2523     while ( startElem || !startLinks.empty() ) {
2524       while ( !startElem && !startLinks.empty() ) {
2525         // Get an element to start, by a link
2526         SMESH_TLink linkId = startLinks.front();
2527         startLinks.pop_front();
2528         itLE = mapLi_listEl.find( linkId );
2529         if ( itLE != mapLi_listEl.end() ) {
2530           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2531           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2532           for ( ; itE != listElem.end() ; itE++ )
2533             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2534               startElem = (*itE);
2535           mapLi_listEl.erase( itLE );
2536         }
2537       }
2538
2539       if ( startElem ) {
2540         // Get candidates to be fused
2541         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2542         const SMESH_TLink *link12, *link13;
2543         startElem = 0;
2544         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2545         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2546         ASSERT( !setLi.empty() );
2547         set< SMESH_TLink >::iterator itLi;
2548         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2549         {
2550           const SMESH_TLink & link = (*itLi);
2551           itLE = mapLi_listEl.find( link );
2552           if ( itLE == mapLi_listEl.end() )
2553             continue;
2554
2555           const SMDS_MeshElement* elem = (*itLE).second.front();
2556           if ( elem == tr1 )
2557             elem = (*itLE).second.back();
2558           mapLi_listEl.erase( itLE );
2559           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2560             continue;
2561           if ( tr2 ) {
2562             tr3 = elem;
2563             link13 = &link;
2564           }
2565           else {
2566             tr2 = elem;
2567             link12 = &link;
2568           }
2569
2570           // add other links of elem to list of links to re-start from
2571           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2572           set< SMESH_TLink >::iterator it;
2573           for ( it = links.begin(); it != links.end(); it++ ) {
2574             const SMESH_TLink& link2 = (*it);
2575             if ( link2 != link )
2576               startLinks.push_back( link2 );
2577           }
2578         }
2579
2580         // Get nodes of possible quadrangles
2581         const SMDS_MeshNode *n12 [4], *n13 [4];
2582         bool Ok12 = false, Ok13 = false;
2583         const SMDS_MeshNode *linkNode1, *linkNode2;
2584         if(tr2) {
2585           linkNode1 = link12->first;
2586           linkNode2 = link12->second;
2587           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2588             Ok12 = true;
2589         }
2590         if(tr3) {
2591           linkNode1 = link13->first;
2592           linkNode2 = link13->second;
2593           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2594             Ok13 = true;
2595         }
2596
2597         // Choose a pair to fuse
2598         if ( Ok12 && Ok13 ) {
2599           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2600           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2601           double aBadRate12 = getBadRate( &quad12, theCrit );
2602           double aBadRate13 = getBadRate( &quad13, theCrit );
2603           if (  aBadRate13 < aBadRate12 )
2604             Ok12 = false;
2605           else
2606             Ok13 = false;
2607         }
2608
2609         // Make quadrangles
2610         // and remove fused elems and remove links from the maps
2611         mapEl_setLi.erase( tr1 );
2612         if ( Ok12 )
2613         {
2614           mapEl_setLi.erase( tr2 );
2615           mapLi_listEl.erase( *link12 );
2616           if ( tr1->NbNodes() == 3 )
2617           {
2618             const SMDS_MeshElement* newElem = 0;
2619             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2620             myLastCreatedElems.Append(newElem);
2621             AddToSameGroups( newElem, tr1, aMesh );
2622             int aShapeId = tr1->getshapeId();
2623             if ( aShapeId )
2624               aMesh->SetMeshElementOnShape( newElem, aShapeId );
2625             aMesh->RemoveElement( tr1 );
2626             aMesh->RemoveElement( tr2 );
2627           }
2628           else {
2629             vector< const SMDS_MeshNode* > N1;
2630             vector< const SMDS_MeshNode* > N2;
2631             getNodesFromTwoTria(tr1,tr2,N1,N2);
2632             // now we receive following N1 and N2 (using numeration as in image in InverseDiag())
2633             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2634             // i.e. first nodes from both arrays form a new diagonal
2635             const SMDS_MeshNode* aNodes[8];
2636             aNodes[0] = N1[0];
2637             aNodes[1] = N1[1];
2638             aNodes[2] = N2[0];
2639             aNodes[3] = N2[1];
2640             aNodes[4] = N1[3];
2641             aNodes[5] = N2[5];
2642             aNodes[6] = N2[3];
2643             aNodes[7] = N1[5];
2644             const SMDS_MeshElement* newElem = 0;
2645             if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
2646               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2647                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
2648             else
2649               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2650                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2651             myLastCreatedElems.Append(newElem);
2652             AddToSameGroups( newElem, tr1, aMesh );
2653             int aShapeId = tr1->getshapeId();
2654             if ( aShapeId )
2655               aMesh->SetMeshElementOnShape( newElem, aShapeId );
2656             aMesh->RemoveElement( tr1 );
2657             aMesh->RemoveElement( tr2 );
2658             // remove middle node (9)
2659             if ( N1[4]->NbInverseElements() == 0 )
2660               aMesh->RemoveNode( N1[4] );
2661             if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
2662               aMesh->RemoveNode( N1[6] );
2663             if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
2664               aMesh->RemoveNode( N2[6] );
2665           }
2666         }
2667         else if ( Ok13 )
2668         {
2669           mapEl_setLi.erase( tr3 );
2670           mapLi_listEl.erase( *link13 );
2671           if ( tr1->NbNodes() == 3 ) {
2672             const SMDS_MeshElement* newElem = 0;
2673             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2674             myLastCreatedElems.Append(newElem);
2675             AddToSameGroups( newElem, tr1, aMesh );
2676             int aShapeId = tr1->getshapeId();
2677             if ( aShapeId )
2678               aMesh->SetMeshElementOnShape( newElem, aShapeId );
2679             aMesh->RemoveElement( tr1 );
2680             aMesh->RemoveElement( tr3 );
2681           }
2682           else {
2683             vector< const SMDS_MeshNode* > N1;
2684             vector< const SMDS_MeshNode* > N2;
2685             getNodesFromTwoTria(tr1,tr3,N1,N2);
2686             // now we receive following N1 and N2 (using numeration as above image)
2687             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2688             // i.e. first nodes from both arrays form a new diagonal
2689             const SMDS_MeshNode* aNodes[8];
2690             aNodes[0] = N1[0];
2691             aNodes[1] = N1[1];
2692             aNodes[2] = N2[0];
2693             aNodes[3] = N2[1];
2694             aNodes[4] = N1[3];
2695             aNodes[5] = N2[5];
2696             aNodes[6] = N2[3];
2697             aNodes[7] = N1[5];
2698             const SMDS_MeshElement* newElem = 0;
2699             if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
2700               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2701                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
2702             else
2703               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2704                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2705             myLastCreatedElems.Append(newElem);
2706             AddToSameGroups( newElem, tr1, aMesh );
2707             int aShapeId = tr1->getshapeId();
2708             if ( aShapeId )
2709               aMesh->SetMeshElementOnShape( newElem, aShapeId );
2710             aMesh->RemoveElement( tr1 );
2711             aMesh->RemoveElement( tr3 );
2712             // remove middle node (9)
2713             if ( N1[4]->NbInverseElements() == 0 )
2714               aMesh->RemoveNode( N1[4] );
2715             if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
2716               aMesh->RemoveNode( N1[6] );
2717             if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
2718               aMesh->RemoveNode( N2[6] );
2719           }
2720         }
2721
2722         // Next element to fuse: the rejected one
2723         if ( tr3 )
2724           startElem = Ok12 ? tr3 : tr2;
2725
2726       } // if ( startElem )
2727     } // while ( startElem || !startLinks.empty() )
2728   } // while ( ! mapEl_setLi.empty() )
2729
2730   return true;
2731 }
2732
2733
2734 /*#define DUMPSO(txt) \
2735 //  cout << txt << endl;
2736 //=============================================================================
2737 //
2738 //
2739 //
2740 //=============================================================================
2741 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2742 {
2743 if ( i1 == i2 )
2744 return;
2745 int tmp = idNodes[ i1 ];
2746 idNodes[ i1 ] = idNodes[ i2 ];
2747 idNodes[ i2 ] = tmp;
2748 gp_Pnt Ptmp = P[ i1 ];
2749 P[ i1 ] = P[ i2 ];
2750 P[ i2 ] = Ptmp;
2751 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2752 }
2753
2754 //=======================================================================
2755 //function : SortQuadNodes
2756 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2757 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2758 //           1 or 2 else 0.
2759 //=======================================================================
2760
2761 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2762 int               idNodes[] )
2763 {
2764   gp_Pnt P[4];
2765   int i;
2766   for ( i = 0; i < 4; i++ ) {
2767     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2768     if ( !n ) return 0;
2769     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2770   }
2771
2772   gp_Vec V1(P[0], P[1]);
2773   gp_Vec V2(P[0], P[2]);
2774   gp_Vec V3(P[0], P[3]);
2775
2776   gp_Vec Cross1 = V1 ^ V2;
2777   gp_Vec Cross2 = V2 ^ V3;
2778
2779   i = 0;
2780   if (Cross1.Dot(Cross2) < 0)
2781   {
2782     Cross1 = V2 ^ V1;
2783     Cross2 = V1 ^ V3;
2784
2785     if (Cross1.Dot(Cross2) < 0)
2786       i = 2;
2787     else
2788       i = 1;
2789     swap ( i, i + 1, idNodes, P );
2790
2791     //     for ( int ii = 0; ii < 4; ii++ ) {
2792     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2793     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2794     //     }
2795   }
2796   return i;
2797 }
2798
2799 //=======================================================================
2800 //function : SortHexaNodes
2801 //purpose  : Set 8 nodes of a hexahedron in a good order.
2802 //           Return success status
2803 //=======================================================================
2804
2805 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2806                                       int               idNodes[] )
2807 {
2808   gp_Pnt P[8];
2809   int i;
2810   DUMPSO( "INPUT: ========================================");
2811   for ( i = 0; i < 8; i++ ) {
2812     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2813     if ( !n ) return false;
2814     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2815     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2816   }
2817   DUMPSO( "========================================");
2818
2819
2820   set<int> faceNodes;  // ids of bottom face nodes, to be found
2821   set<int> checkedId1; // ids of tried 2-nd nodes
2822   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2823   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2824   int iMin, iLoop1 = 0;
2825
2826   // Loop to try the 2-nd nodes
2827
2828   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2829   {
2830     // Find not checked 2-nd node
2831     for ( i = 1; i < 8; i++ )
2832       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2833         int id1 = idNodes[i];
2834         swap ( 1, i, idNodes, P );
2835         checkedId1.insert ( id1 );
2836         break;
2837       }
2838
2839     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2840     // ie that all but meybe one (id3 which is on the same face) nodes
2841     // lay on the same side from the triangle plane.
2842
2843     bool manyInPlane = false; // more than 4 nodes lay in plane
2844     int iLoop2 = 0;
2845     while ( ++iLoop2 < 6 ) {
2846
2847       // get 1-2-3 plane coeffs
2848       Standard_Real A, B, C, D;
2849       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2850       if ( N.SquareMagnitude() > gp::Resolution() )
2851       {
2852         gp_Pln pln ( P[0], N );
2853         pln.Coefficients( A, B, C, D );
2854
2855         // find the node (iMin) closest to pln
2856         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2857         set<int> idInPln;
2858         for ( i = 3; i < 8; i++ ) {
2859           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2860           if ( fabs( dist[i] ) < minDist ) {
2861             minDist = fabs( dist[i] );
2862             iMin = i;
2863           }
2864           if ( fabs( dist[i] ) <= tol )
2865             idInPln.insert( idNodes[i] );
2866         }
2867
2868         // there should not be more than 4 nodes in bottom plane
2869         if ( idInPln.size() > 1 )
2870         {
2871           DUMPSO( "### idInPln.size() = " << idInPln.size());
2872           // idInPlane does not contain the first 3 nodes
2873           if ( manyInPlane || idInPln.size() == 5)
2874             return false; // all nodes in one plane
2875           manyInPlane = true;
2876
2877           // set the 1-st node to be not in plane
2878           for ( i = 3; i < 8; i++ ) {
2879             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2880               DUMPSO( "### Reset 0-th node");
2881               swap( 0, i, idNodes, P );
2882               break;
2883             }
2884           }
2885
2886           // reset to re-check second nodes
2887           leastDist = DBL_MAX;
2888           faceNodes.clear();
2889           checkedId1.clear();
2890           iLoop1 = 0;
2891           break; // from iLoop2;
2892         }
2893
2894         // check that the other 4 nodes are on the same side
2895         bool sameSide = true;
2896         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2897         for ( i = 3; sameSide && i < 8; i++ ) {
2898           if ( i != iMin )
2899             sameSide = ( isNeg == dist[i] <= 0.);
2900         }
2901
2902         // keep best solution
2903         if ( sameSide && minDist < leastDist ) {
2904           leastDist = minDist;
2905           faceNodes.clear();
2906           faceNodes.insert( idNodes[ 1 ] );
2907           faceNodes.insert( idNodes[ 2 ] );
2908           faceNodes.insert( idNodes[ iMin ] );
2909           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2910                   << " leastDist = " << leastDist);
2911           if ( leastDist <= DBL_MIN )
2912             break;
2913         }
2914       }
2915
2916       // set next 3-d node to check
2917       int iNext = 2 + iLoop2;
2918       if ( iNext < 8 ) {
2919         DUMPSO( "Try 2-nd");
2920         swap ( 2, iNext, idNodes, P );
2921       }
2922     } // while ( iLoop2 < 6 )
2923   } // iLoop1
2924
2925   if ( faceNodes.empty() ) return false;
2926
2927   // Put the faceNodes in proper places
2928   for ( i = 4; i < 8; i++ ) {
2929     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2930       // find a place to put
2931       int iTo = 1;
2932       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2933         iTo++;
2934       DUMPSO( "Set faceNodes");
2935       swap ( iTo, i, idNodes, P );
2936     }
2937   }
2938
2939
2940   // Set nodes of the found bottom face in good order
2941   DUMPSO( " Found bottom face: ");
2942   i = SortQuadNodes( theMesh, idNodes );
2943   if ( i ) {
2944     gp_Pnt Ptmp = P[ i ];
2945     P[ i ] = P[ i+1 ];
2946     P[ i+1 ] = Ptmp;
2947   }
2948   //   else
2949   //     for ( int ii = 0; ii < 4; ii++ ) {
2950   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2951   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2952   //    }
2953
2954   // Gravity center of the top and bottom faces
2955   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2956   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2957
2958   // Get direction from the bottom to the top face
2959   gp_Vec upDir ( aGCb, aGCt );
2960   Standard_Real upDirSize = upDir.Magnitude();
2961   if ( upDirSize <= gp::Resolution() ) return false;
2962   upDir / upDirSize;
2963
2964   // Assure that the bottom face normal points up
2965   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2966   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2967   if ( Nb.Dot( upDir ) < 0 ) {
2968     DUMPSO( "Reverse bottom face");
2969     swap( 1, 3, idNodes, P );
2970   }
2971
2972   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2973   Standard_Real minDist = DBL_MAX;
2974   for ( i = 4; i < 8; i++ ) {
2975     // projection of P[i] to the plane defined by P[0] and upDir
2976     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2977     Standard_Real sqDist = P[0].SquareDistance( Pp );
2978     if ( sqDist < minDist ) {
2979       minDist = sqDist;
2980       iMin = i;
2981     }
2982   }
2983   DUMPSO( "Set 4-th");
2984   swap ( 4, iMin, idNodes, P );
2985
2986   // Set nodes of the top face in good order
2987   DUMPSO( "Sort top face");
2988   i = SortQuadNodes( theMesh, &idNodes[4] );
2989   if ( i ) {
2990     i += 4;
2991     gp_Pnt Ptmp = P[ i ];
2992     P[ i ] = P[ i+1 ];
2993     P[ i+1 ] = Ptmp;
2994   }
2995
2996   // Assure that direction of the top face normal is from the bottom face
2997   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2998   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2999   if ( Nt.Dot( upDir ) < 0 ) {
3000     DUMPSO( "Reverse top face");
3001     swap( 5, 7, idNodes, P );
3002   }
3003
3004   //   DUMPSO( "OUTPUT: ========================================");
3005   //   for ( i = 0; i < 8; i++ ) {
3006   //     float *p = ugrid->GetPoint(idNodes[i]);
3007   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
3008   //   }
3009
3010   return true;
3011 }*/
3012
3013 //================================================================================
3014 /*!
3015  * \brief Return nodes linked to the given one
3016  * \param theNode - the node
3017  * \param linkedNodes - the found nodes
3018  * \param type - the type of elements to check
3019  *
3020  * Medium nodes are ignored
3021  */
3022 //================================================================================
3023
3024 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
3025                                        TIDSortedElemSet &   linkedNodes,
3026                                        SMDSAbs_ElementType  type )
3027 {
3028   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
3029   while ( elemIt->more() )
3030   {
3031     const SMDS_MeshElement* elem = elemIt->next();
3032     if(elem->GetType() == SMDSAbs_0DElement)
3033       continue;
3034
3035     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
3036     if ( elem->GetType() == SMDSAbs_Volume )
3037     {
3038       SMDS_VolumeTool vol( elem );
3039       while ( nodeIt->more() ) {
3040         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
3041         if ( theNode != n && vol.IsLinked( theNode, n ))
3042           linkedNodes.insert( n );
3043       }
3044     }
3045     else
3046     {
3047       for ( int i = 0; nodeIt->more(); ++i ) {
3048         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
3049         if ( n == theNode ) {
3050           int iBefore = i - 1;
3051           int iAfter  = i + 1;
3052           if ( elem->IsQuadratic() ) {
3053             int nb = elem->NbNodes() / 2;
3054             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
3055             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
3056           }
3057           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
3058           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
3059         }
3060       }
3061     }
3062   }
3063 }
3064
3065 //=======================================================================
3066 //function : laplacianSmooth
3067 //purpose  : pulls theNode toward the center of surrounding nodes directly
3068 //           connected to that node along an element edge
3069 //=======================================================================
3070
3071 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
3072                      const Handle(Geom_Surface)&          theSurface,
3073                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3074 {
3075   // find surrounding nodes
3076
3077   TIDSortedElemSet nodeSet;
3078   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
3079
3080   // compute new coodrs
3081
3082   double coord[] = { 0., 0., 0. };
3083   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
3084   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
3085     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
3086     if ( theSurface.IsNull() ) { // smooth in 3D
3087       coord[0] += node->X();
3088       coord[1] += node->Y();
3089       coord[2] += node->Z();
3090     }
3091     else { // smooth in 2D
3092       ASSERT( theUVMap.find( node ) != theUVMap.end() );
3093       gp_XY* uv = theUVMap[ node ];
3094       coord[0] += uv->X();
3095       coord[1] += uv->Y();
3096     }
3097   }
3098   int nbNodes = nodeSet.size();
3099   if ( !nbNodes )
3100     return;
3101   coord[0] /= nbNodes;
3102   coord[1] /= nbNodes;
3103
3104   if ( !theSurface.IsNull() ) {
3105     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
3106     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
3107     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
3108     coord[0] = p3d.X();
3109     coord[1] = p3d.Y();
3110     coord[2] = p3d.Z();
3111   }
3112   else
3113     coord[2] /= nbNodes;
3114
3115   // move node
3116
3117   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
3118 }
3119
3120 //=======================================================================
3121 //function : centroidalSmooth
3122 //purpose  : pulls theNode toward the element-area-weighted centroid of the
3123 //           surrounding elements
3124 //=======================================================================
3125
3126 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
3127                       const Handle(Geom_Surface)&          theSurface,
3128                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3129 {
3130   gp_XYZ aNewXYZ(0.,0.,0.);
3131   SMESH::Controls::Area anAreaFunc;
3132   double totalArea = 0.;
3133   int nbElems = 0;
3134
3135   // compute new XYZ
3136
3137   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
3138   while ( elemIt->more() )
3139   {
3140     const SMDS_MeshElement* elem = elemIt->next();
3141     nbElems++;
3142
3143     gp_XYZ elemCenter(0.,0.,0.);
3144     SMESH::Controls::TSequenceOfXYZ aNodePoints;
3145     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3146     int nn = elem->NbNodes();
3147     if(elem->IsQuadratic()) nn = nn/2;
3148     int i=0;
3149     //while ( itN->more() ) {
3150     while ( i<nn ) {
3151       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
3152       i++;
3153       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
3154       aNodePoints.push_back( aP );
3155       if ( !theSurface.IsNull() ) { // smooth in 2D
3156         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
3157         gp_XY* uv = theUVMap[ aNode ];
3158         aP.SetCoord( uv->X(), uv->Y(), 0. );
3159       }
3160       elemCenter += aP;
3161     }
3162     double elemArea = anAreaFunc.GetValue( aNodePoints );
3163     totalArea += elemArea;
3164     elemCenter /= nn;
3165     aNewXYZ += elemCenter * elemArea;
3166   }
3167   aNewXYZ /= totalArea;
3168   if ( !theSurface.IsNull() ) {
3169     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
3170     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
3171   }
3172
3173   // move node
3174
3175   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
3176 }
3177
3178 //=======================================================================
3179 //function : getClosestUV
3180 //purpose  : return UV of closest projection
3181 //=======================================================================
3182
3183 static bool getClosestUV (Extrema_GenExtPS& projector,
3184                           const gp_Pnt&     point,
3185                           gp_XY &           result)
3186 {
3187   projector.Perform( point );
3188   if ( projector.IsDone() ) {
3189     double u, v, minVal = DBL_MAX;
3190     for ( int i = projector.NbExt(); i > 0; i-- )
3191 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
3192       if ( projector.SquareDistance( i ) < minVal ) {
3193         minVal = projector.SquareDistance( i );
3194 #else
3195       if ( projector.Value( i ) < minVal ) {
3196         minVal = projector.Value( i );
3197 #endif
3198         projector.Point( i ).Parameter( u, v );
3199       }
3200     result.SetCoord( u, v );
3201     return true;
3202   }
3203   return false;
3204 }
3205
3206 //=======================================================================
3207 //function : Smooth
3208 //purpose  : Smooth theElements during theNbIterations or until a worst
3209 //           element has aspect ratio <= theTgtAspectRatio.
3210 //           Aspect Ratio varies in range [1.0, inf].
3211 //           If theElements is empty, the whole mesh is smoothed.
3212 //           theFixedNodes contains additionally fixed nodes. Nodes built
3213 //           on edges and boundary nodes are always fixed.
3214 //=======================================================================
3215
3216 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
3217                                set<const SMDS_MeshNode*> & theFixedNodes,
3218                                const SmoothMethod          theSmoothMethod,
3219                                const int                   theNbIterations,
3220                                double                      theTgtAspectRatio,
3221                                const bool                  the2D)
3222 {
3223   myLastCreatedElems.Clear();
3224   myLastCreatedNodes.Clear();
3225
3226   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
3227
3228   if ( theTgtAspectRatio < 1.0 )
3229     theTgtAspectRatio = 1.0;
3230
3231   const double disttol = 1.e-16;
3232
3233   SMESH::Controls::AspectRatio aQualityFunc;
3234
3235   SMESHDS_Mesh* aMesh = GetMeshDS();
3236
3237   if ( theElems.empty() ) {
3238     // add all faces to theElems
3239     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
3240     while ( fIt->more() ) {
3241       const SMDS_MeshElement* face = fIt->next();
3242       theElems.insert( theElems.end(), face );
3243     }
3244   }
3245   // get all face ids theElems are on
3246   set< int > faceIdSet;
3247   TIDSortedElemSet::iterator itElem;
3248   if ( the2D )
3249     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3250       int fId = FindShape( *itElem );
3251       // check that corresponding submesh exists and a shape is face
3252       if (fId &&
3253           faceIdSet.find( fId ) == faceIdSet.end() &&
3254           aMesh->MeshElements( fId )) {
3255         TopoDS_Shape F = aMesh->IndexToShape( fId );
3256         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
3257           faceIdSet.insert( fId );
3258       }
3259     }
3260   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
3261
3262   // ===============================================
3263   // smooth elements on each TopoDS_Face separately
3264   // ===============================================
3265
3266   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
3267   for ( ; fId != faceIdSet.rend(); ++fId ) {
3268     // get face surface and submesh
3269     Handle(Geom_Surface) surface;
3270     SMESHDS_SubMesh* faceSubMesh = 0;
3271     TopoDS_Face face;
3272     double fToler2 = 0, f,l;
3273     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
3274     bool isUPeriodic = false, isVPeriodic = false;
3275     if ( *fId ) {
3276       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
3277       surface = BRep_Tool::Surface( face );
3278       faceSubMesh = aMesh->MeshElements( *fId );
3279       fToler2 = BRep_Tool::Tolerance( face );
3280       fToler2 *= fToler2 * 10.;
3281       isUPeriodic = surface->IsUPeriodic();
3282       if ( isUPeriodic )
3283         surface->UPeriod();
3284       isVPeriodic = surface->IsVPeriodic();
3285       if ( isVPeriodic )
3286         surface->VPeriod();
3287       surface->Bounds( u1, u2, v1, v2 );
3288     }
3289     // ---------------------------------------------------------
3290     // for elements on a face, find movable and fixed nodes and
3291     // compute UV for them
3292     // ---------------------------------------------------------
3293     bool checkBoundaryNodes = false;
3294     bool isQuadratic = false;
3295     set<const SMDS_MeshNode*> setMovableNodes;
3296     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3297     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3298     list< const SMDS_MeshElement* > elemsOnFace;
3299
3300     Extrema_GenExtPS projector;
3301     GeomAdaptor_Surface surfAdaptor;
3302     if ( !surface.IsNull() ) {
3303       surfAdaptor.Load( surface );
3304       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3305     }
3306     int nbElemOnFace = 0;
3307     itElem = theElems.begin();
3308     // loop on not yet smoothed elements: look for elems on a face
3309     while ( itElem != theElems.end() ) {
3310       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3311         break; // all elements found
3312
3313       const SMDS_MeshElement* elem = *itElem;
3314       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3315            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3316         ++itElem;
3317         continue;
3318       }
3319       elemsOnFace.push_back( elem );
3320       theElems.erase( itElem++ );
3321       nbElemOnFace++;
3322
3323       if ( !isQuadratic )
3324         isQuadratic = elem->IsQuadratic();
3325
3326       // get movable nodes of elem
3327       const SMDS_MeshNode* node;
3328       SMDS_TypeOfPosition posType;
3329       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3330       int nn = 0, nbn =  elem->NbNodes();
3331       if(elem->IsQuadratic())
3332         nbn = nbn/2;
3333       while ( nn++ < nbn ) {
3334         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3335         const SMDS_PositionPtr& pos = node->GetPosition();
3336         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3337         if (posType != SMDS_TOP_EDGE &&
3338             posType != SMDS_TOP_VERTEX &&
3339             theFixedNodes.find( node ) == theFixedNodes.end())
3340         {
3341           // check if all faces around the node are on faceSubMesh
3342           // because a node on edge may be bound to face
3343           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3344           bool all = true;
3345           if ( faceSubMesh ) {
3346             while ( eIt->more() && all ) {
3347               const SMDS_MeshElement* e = eIt->next();
3348               all = faceSubMesh->Contains( e );
3349             }
3350           }
3351           if ( all )
3352             setMovableNodes.insert( node );
3353           else
3354             checkBoundaryNodes = true;
3355         }
3356         if ( posType == SMDS_TOP_3DSPACE )
3357           checkBoundaryNodes = true;
3358       }
3359
3360       if ( surface.IsNull() )
3361         continue;
3362
3363       // get nodes to check UV
3364       list< const SMDS_MeshNode* > uvCheckNodes;
3365       itN = elem->nodesIterator();
3366       nn = 0; nbn =  elem->NbNodes();
3367       if(elem->IsQuadratic())
3368         nbn = nbn/2;
3369       while ( nn++ < nbn ) {
3370         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3371         if ( uvMap.find( node ) == uvMap.end() )
3372           uvCheckNodes.push_back( node );
3373         // add nodes of elems sharing node
3374         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3375         //         while ( eIt->more() ) {
3376         //           const SMDS_MeshElement* e = eIt->next();
3377         //           if ( e != elem ) {
3378         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3379         //             while ( nIt->more() ) {
3380         //               const SMDS_MeshNode* n =
3381         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3382         //               if ( uvMap.find( n ) == uvMap.end() )
3383         //                 uvCheckNodes.push_back( n );
3384         //             }
3385         //           }
3386         //         }
3387       }
3388       // check UV on face
3389       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3390       for ( ; n != uvCheckNodes.end(); ++n ) {
3391         node = *n;
3392         gp_XY uv( 0, 0 );
3393         const SMDS_PositionPtr& pos = node->GetPosition();
3394         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3395         // get existing UV
3396         switch ( posType ) {
3397         case SMDS_TOP_FACE: {
3398           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3399           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3400           break;
3401         }
3402         case SMDS_TOP_EDGE: {
3403           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3404           Handle(Geom2d_Curve) pcurve;
3405           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3406             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3407           if ( !pcurve.IsNull() ) {
3408             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3409             uv = pcurve->Value( u ).XY();
3410           }
3411           break;
3412         }
3413         case SMDS_TOP_VERTEX: {
3414           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3415           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3416             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3417           break;
3418         }
3419         default:;
3420         }
3421         // check existing UV
3422         bool project = true;
3423         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3424         double dist1 = DBL_MAX, dist2 = 0;
3425         if ( posType != SMDS_TOP_3DSPACE ) {
3426           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3427           project = dist1 > fToler2;
3428         }
3429         if ( project ) { // compute new UV
3430           gp_XY newUV;
3431           if ( !getClosestUV( projector, pNode, newUV )) {
3432             MESSAGE("Node Projection Failed " << node);
3433           }
3434           else {
3435             if ( isUPeriodic )
3436               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3437             if ( isVPeriodic )
3438               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3439             // check new UV
3440             if ( posType != SMDS_TOP_3DSPACE )
3441               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3442             if ( dist2 < dist1 )
3443               uv = newUV;
3444           }
3445         }
3446         // store UV in the map
3447         listUV.push_back( uv );
3448         uvMap.insert( make_pair( node, &listUV.back() ));
3449       }
3450     } // loop on not yet smoothed elements
3451
3452     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3453       checkBoundaryNodes = true;
3454
3455     // fix nodes on mesh boundary
3456
3457     if ( checkBoundaryNodes ) {
3458       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3459       map< SMESH_TLink, int >::iterator link_nb;
3460       // put all elements links to linkNbMap
3461       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3462       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3463         const SMDS_MeshElement* elem = (*elemIt);
3464         int nbn =  elem->NbCornerNodes();
3465         // loop on elem links: insert them in linkNbMap
3466         for ( int iN = 0; iN < nbn; ++iN ) {
3467           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3468           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3469           SMESH_TLink link( n1, n2 );
3470           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3471           link_nb->second++;
3472         }
3473       }
3474       // remove nodes that are in links encountered only once from setMovableNodes
3475       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3476         if ( link_nb->second == 1 ) {
3477           setMovableNodes.erase( link_nb->first.node1() );
3478           setMovableNodes.erase( link_nb->first.node2() );
3479         }
3480       }
3481     }
3482
3483     // -----------------------------------------------------
3484     // for nodes on seam edge, compute one more UV ( uvMap2 );
3485     // find movable nodes linked to nodes on seam and which
3486     // are to be smoothed using the second UV ( uvMap2 )
3487     // -----------------------------------------------------
3488
3489     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3490     if ( !surface.IsNull() ) {
3491       TopExp_Explorer eExp( face, TopAbs_EDGE );
3492       for ( ; eExp.More(); eExp.Next() ) {
3493         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3494         if ( !BRep_Tool::IsClosed( edge, face ))
3495           continue;
3496         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3497         if ( !sm ) continue;
3498         // find out which parameter varies for a node on seam
3499         double f,l;
3500         gp_Pnt2d uv1, uv2;
3501         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3502         if ( pcurve.IsNull() ) continue;
3503         uv1 = pcurve->Value( f );
3504         edge.Reverse();
3505         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3506         if ( pcurve.IsNull() ) continue;
3507         uv2 = pcurve->Value( f );
3508         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3509         // assure uv1 < uv2
3510         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3511           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3512         }
3513         // get nodes on seam and its vertices
3514         list< const SMDS_MeshNode* > seamNodes;
3515         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3516         while ( nSeamIt->more() ) {
3517           const SMDS_MeshNode* node = nSeamIt->next();
3518           if ( !isQuadratic || !IsMedium( node ))
3519             seamNodes.push_back( node );
3520         }
3521         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3522         for ( ; vExp.More(); vExp.Next() ) {
3523           sm = aMesh->MeshElements( vExp.Current() );
3524           if ( sm ) {
3525             nSeamIt = sm->GetNodes();
3526             while ( nSeamIt->more() )
3527               seamNodes.push_back( nSeamIt->next() );
3528           }
3529         }
3530         // loop on nodes on seam
3531         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3532         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3533           const SMDS_MeshNode* nSeam = *noSeIt;
3534           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3535           if ( n_uv == uvMap.end() )
3536             continue;
3537           // set the first UV
3538           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3539           // set the second UV
3540           listUV.push_back( *n_uv->second );
3541           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3542           if ( uvMap2.empty() )
3543             uvMap2 = uvMap; // copy the uvMap contents
3544           uvMap2[ nSeam ] = &listUV.back();
3545
3546           // collect movable nodes linked to ones on seam in nodesNearSeam
3547           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3548           while ( eIt->more() ) {
3549             const SMDS_MeshElement* e = eIt->next();
3550             int nbUseMap1 = 0, nbUseMap2 = 0;
3551             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3552             int nn = 0, nbn =  e->NbNodes();
3553             if(e->IsQuadratic()) nbn = nbn/2;
3554             while ( nn++ < nbn )
3555             {
3556               const SMDS_MeshNode* n =
3557                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3558               if (n == nSeam ||
3559                   setMovableNodes.find( n ) == setMovableNodes.end() )
3560                 continue;
3561               // add only nodes being closer to uv2 than to uv1
3562               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3563                            0.5 * ( n->Y() + nSeam->Y() ),
3564                            0.5 * ( n->Z() + nSeam->Z() ));
3565               gp_XY uv;
3566               getClosestUV( projector, pMid, uv );
3567               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3568                 nodesNearSeam.insert( n );
3569                 nbUseMap2++;
3570               }
3571               else
3572                 nbUseMap1++;
3573             }
3574             // for centroidalSmooth all element nodes must
3575             // be on one side of a seam
3576             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3577               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3578               nn = 0;
3579               while ( nn++ < nbn ) {
3580                 const SMDS_MeshNode* n =
3581                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3582                 setMovableNodes.erase( n );
3583               }
3584             }
3585           }
3586         } // loop on nodes on seam
3587       } // loop on edge of a face
3588     } // if ( !face.IsNull() )
3589
3590     if ( setMovableNodes.empty() ) {
3591       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3592       continue; // goto next face
3593     }
3594
3595     // -------------
3596     // SMOOTHING //
3597     // -------------
3598
3599     int it = -1;
3600     double maxRatio = -1., maxDisplacement = -1.;
3601     set<const SMDS_MeshNode*>::iterator nodeToMove;
3602     for ( it = 0; it < theNbIterations; it++ ) {
3603       maxDisplacement = 0.;
3604       nodeToMove = setMovableNodes.begin();
3605       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3606         const SMDS_MeshNode* node = (*nodeToMove);
3607         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3608
3609         // smooth
3610         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3611         if ( theSmoothMethod == LAPLACIAN )
3612           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3613         else
3614           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3615
3616         // node displacement
3617         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3618         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3619         if ( aDispl > maxDisplacement )
3620           maxDisplacement = aDispl;
3621       }
3622       // no node movement => exit
3623       //if ( maxDisplacement < 1.e-16 ) {
3624       if ( maxDisplacement < disttol ) {
3625         MESSAGE("-- no node movement --");
3626         break;
3627       }
3628
3629       // check elements quality
3630       maxRatio  = 0;
3631       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3632       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3633         const SMDS_MeshElement* elem = (*elemIt);
3634         if ( !elem || elem->GetType() != SMDSAbs_Face )
3635           continue;
3636         SMESH::Controls::TSequenceOfXYZ aPoints;
3637         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3638           double aValue = aQualityFunc.GetValue( aPoints );
3639           if ( aValue > maxRatio )
3640             maxRatio = aValue;
3641         }
3642       }
3643       if ( maxRatio <= theTgtAspectRatio ) {
3644         MESSAGE("-- quality achived --");
3645         break;
3646       }
3647       if (it+1 == theNbIterations) {
3648         MESSAGE("-- Iteration limit exceeded --");
3649       }
3650     } // smoothing iterations
3651
3652     MESSAGE(" Face id: " << *fId <<
3653             " Nb iterstions: " << it <<
3654             " Displacement: " << maxDisplacement <<
3655             " Aspect Ratio " << maxRatio);
3656
3657     // ---------------------------------------
3658     // new nodes positions are computed,
3659     // record movement in DS and set new UV
3660     // ---------------------------------------
3661     nodeToMove = setMovableNodes.begin();
3662     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3663       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3664       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3665       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3666       if ( node_uv != uvMap.end() ) {
3667         gp_XY* uv = node_uv->second;
3668         node->SetPosition
3669           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3670       }
3671     }
3672
3673     // move medium nodes of quadratic elements
3674     if ( isQuadratic )
3675     {
3676       SMESH_MesherHelper helper( *GetMesh() );
3677       helper.SetSubShape( face );
3678       vector<const SMDS_MeshNode*> nodes;
3679       bool checkUV;
3680       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3681       for ( ; elemIt != elemsOnFace.end(); ++elemIt )
3682       {
3683         const SMDS_MeshElement* QF = *elemIt;
3684         if ( QF->IsQuadratic() )
3685         {
3686           nodes.assign( SMDS_MeshElement::iterator( QF->interlacedNodesElemIterator() ),
3687                         SMDS_MeshElement::iterator() );
3688           nodes.push_back( nodes[0] );
3689           gp_Pnt xyz;
3690           for (size_t i = 1; i < nodes.size(); i += 2 ) // i points to a medium node
3691           {
3692             if ( !surface.IsNull() )
3693             {
3694               gp_XY uv1 = helper.GetNodeUV( face, nodes[i-1], nodes[i+1], &checkUV );
3695               gp_XY uv2 = helper.GetNodeUV( face, nodes[i+1], nodes[i-1], &checkUV );
3696               gp_XY uv  = helper.GetMiddleUV( surface, uv1, uv2 );
3697               xyz = surface->Value( uv.X(), uv.Y() );
3698             }
3699             else {
3700               xyz = 0.5 * ( SMESH_TNodeXYZ( nodes[i-1] ) + SMESH_TNodeXYZ( nodes[i+1] ));
3701             }
3702             if (( SMESH_TNodeXYZ( nodes[i] ) - xyz.XYZ() ).Modulus() > disttol )
3703               // we have to move a medium node
3704               aMesh->MoveNode( nodes[i], xyz.X(), xyz.Y(), xyz.Z() );
3705           }
3706         }
3707       }
3708     }
3709
3710   } // loop on face ids
3711
3712 }
3713
3714 //=======================================================================
3715 //function : isReverse
3716 //purpose  : Return true if normal of prevNodes is not co-directied with
3717 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3718 //           iNotSame is where prevNodes and nextNodes are different.
3719 //           If result is true then future volume orientation is OK
3720 //=======================================================================
3721
3722 static bool isReverse(const SMDS_MeshElement*             face,
3723                       const vector<const SMDS_MeshNode*>& prevNodes,
3724                       const vector<const SMDS_MeshNode*>& nextNodes,
3725                       const int                           iNotSame)
3726 {
3727
3728   SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
3729   SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
3730   gp_XYZ extrDir( pN - pP ), faceNorm;
3731   SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false );
3732
3733   return faceNorm * extrDir < 0.0;
3734 }
3735
3736 //=======================================================================
3737 /*!
3738  * \brief Create elements by sweeping an element
3739  * \param elem - element to sweep
3740  * \param newNodesItVec - nodes generated from each node of the element
3741  * \param newElems - generated elements
3742  * \param nbSteps - number of sweeping steps
3743  * \param srcElements - to append elem for each generated element
3744  */
3745 //=======================================================================
3746
3747 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3748                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3749                                     list<const SMDS_MeshElement*>&        newElems,
3750                                     const int                             nbSteps,
3751                                     SMESH_SequenceOfElemPtr&              srcElements)
3752 {
3753   //MESSAGE("sweepElement " << nbSteps);
3754   SMESHDS_Mesh* aMesh = GetMeshDS();
3755
3756   const int           nbNodes = elem->NbNodes();
3757   const int         nbCorners = elem->NbCornerNodes();
3758   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of
3759                                                           polyhedron creation !!! */
3760   // Loop on elem nodes:
3761   // find new nodes and detect same nodes indices
3762   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3763   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3764   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3765   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3766
3767   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
3768   vector<int> sames(nbNodes);
3769   vector<bool> isSingleNode(nbNodes);
3770
3771   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3772     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
3773     const SMDS_MeshNode*                         node = nnIt->first;
3774     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3775     if ( listNewNodes.empty() )
3776       return;
3777
3778     itNN   [ iNode ] = listNewNodes.begin();
3779     prevNod[ iNode ] = node;
3780     nextNod[ iNode ] = listNewNodes.front();
3781
3782     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
3783                                                              corner node of linear */
3784     if ( prevNod[ iNode ] != nextNod [ iNode ])
3785       nbDouble += !isSingleNode[iNode];
3786
3787     if( iNode < nbCorners ) { // check corners only
3788       if ( prevNod[ iNode ] == nextNod [ iNode ])
3789         sames[nbSame++] = iNode;
3790       else
3791         iNotSameNode = iNode;
3792     }
3793   }
3794
3795   if ( nbSame == nbNodes || nbSame > 2) {
3796     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3797     return;
3798   }
3799
3800   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
3801   {
3802     // fix nodes order to have bottom normal external
3803     if ( baseType == SMDSEntity_Polygon )
3804     {
3805       std::reverse( itNN.begin(), itNN.end() );
3806       std::reverse( prevNod.begin(), prevNod.end() );
3807       std::reverse( midlNod.begin(), midlNod.end() );
3808       std::reverse( nextNod.begin(), nextNod.end() );
3809       std::reverse( isSingleNode.begin(), isSingleNode.end() );
3810     }
3811     else
3812     {
3813       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
3814       SMDS_MeshCell::applyInterlace( ind, itNN );
3815       SMDS_MeshCell::applyInterlace( ind, prevNod );
3816       SMDS_MeshCell::applyInterlace( ind, nextNod );
3817       SMDS_MeshCell::applyInterlace( ind, midlNod );
3818       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3819       if ( nbSame > 0 )
3820       {
3821         sames[nbSame] = iNotSameNode;
3822         for ( int j = 0; j <= nbSame; ++j )
3823           for ( size_t i = 0; i < ind.size(); ++i )
3824             if ( ind[i] == sames[j] )
3825             {
3826               sames[j] = i;
3827               break;
3828             }
3829         iNotSameNode = sames[nbSame];
3830       }
3831     }
3832   }
3833
3834   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3835   if ( nbSame > 0 ) {
3836     iSameNode    = sames[ nbSame-1 ];
3837     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
3838     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
3839     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3840   }
3841
3842   // make new elements
3843   for (int iStep = 0; iStep < nbSteps; iStep++ )
3844   {
3845     // get next nodes
3846     for ( iNode = 0; iNode < nbNodes; iNode++ )
3847     {
3848       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
3849       nextNod[ iNode ] = *itNN[ iNode ]++;
3850     }
3851
3852     SMDS_MeshElement* aNewElem = 0;
3853     /*if(!elem->IsPoly())*/ {
3854       switch ( baseType ) {
3855       case SMDSEntity_0D:
3856       case SMDSEntity_Node: { // sweep NODE
3857         if ( nbSame == 0 ) {
3858           if ( isSingleNode[0] )
3859             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3860           else
3861             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3862         }
3863         else
3864           return;
3865         break;
3866       }
3867       case SMDSEntity_Edge: { // sweep EDGE
3868         if ( nbDouble == 0 )
3869         {
3870           if ( nbSame == 0 ) // ---> quadrangle
3871             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3872                                       nextNod[ 1 ], nextNod[ 0 ] );
3873           else               // ---> triangle
3874             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3875                                       nextNod[ iNotSameNode ] );
3876         }
3877         else                 // ---> polygon
3878         {
3879           vector<const SMDS_MeshNode*> poly_nodes;
3880           poly_nodes.push_back( prevNod[0] );
3881           poly_nodes.push_back( prevNod[1] );
3882           if ( prevNod[1] != nextNod[1] )
3883           {
3884             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
3885             poly_nodes.push_back( nextNod[1] );
3886           }
3887           if ( prevNod[0] != nextNod[0] )
3888           {
3889             poly_nodes.push_back( nextNod[0] );
3890             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
3891           }
3892           switch ( poly_nodes.size() ) {
3893           case 3:
3894             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
3895             break;
3896           case 4:
3897             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
3898                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
3899             break;
3900           default:
3901             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
3902           }
3903         }
3904         break;
3905       }
3906       case SMDSEntity_Triangle: // TRIANGLE --->
3907         {
3908           if ( nbDouble > 0 ) break;
3909           if ( nbSame == 0 )       // ---> pentahedron
3910             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3911                                          nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
3912
3913           else if ( nbSame == 1 )  // ---> pyramid
3914             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3915                                          nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3916                                          nextNod[ iSameNode ]);
3917
3918           else // 2 same nodes:       ---> tetrahedron
3919             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3920                                          nextNod[ iNotSameNode ]);
3921           break;
3922         }
3923       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
3924         {
3925           if ( nbSame == 2 )
3926             return;
3927           if ( nbDouble+nbSame == 2 )
3928           {
3929             if(nbSame==0) {      // ---> quadratic quadrangle
3930               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3931                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
3932             }
3933             else { //(nbSame==1) // ---> quadratic triangle
3934               if(sames[0]==2) {
3935                 return; // medium node on axis
3936               }
3937               else if(sames[0]==0)
3938                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3939                                           nextNod[2], midlNod[1], prevNod[2]);
3940               else // sames[0]==1
3941                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3942                                           midlNod[0], nextNod[2], prevNod[2]);
3943             }
3944           }
3945           else if ( nbDouble == 3 )
3946           {
3947             if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
3948               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3949                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
3950             }
3951           }
3952           else
3953             return;
3954           break;
3955         }
3956       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
3957         if ( nbDouble > 0 ) break;
3958
3959         if ( nbSame == 0 )       // ---> hexahedron
3960           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
3961                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
3962
3963         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
3964           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3965                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3966                                        nextNod[ iSameNode ]);
3967           newElems.push_back( aNewElem );
3968           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
3969                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3970                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3971         }
3972         else if ( nbSame == 2 ) { // ---> pentahedron
3973           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3974             // iBeforeSame is same too
3975             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3976                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
3977                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3978           else
3979             // iAfterSame is same too
3980             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
3981                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3982                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3983         }
3984         break;
3985       }
3986       case SMDSEntity_Quad_Triangle:  // sweep (Bi)Quadratic TRIANGLE --->
3987       case SMDSEntity_BiQuad_Triangle: /* ??? */ { 
3988         if ( nbDouble+nbSame != 3 ) break;
3989         if(nbSame==0) {
3990           // --->  pentahedron with 15 nodes
3991           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3992                                        nextNod[0], nextNod[1], nextNod[2],
3993                                        prevNod[3], prevNod[4], prevNod[5],
3994                                        nextNod[3], nextNod[4], nextNod[5],
3995                                        midlNod[0], midlNod[1], midlNod[2]);
3996         }
3997         else if(nbSame==1) {
3998           // --->  2d order pyramid of 13 nodes
3999           int apex = iSameNode;
4000           int i0 = ( apex + 1 ) % nbCorners;
4001           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
4002           int i0a = apex + 3;
4003           int i1a = i1 + 3;
4004           int i01 = i0 + 3;
4005           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
4006                                       nextNod[i0], nextNod[i1], prevNod[apex],
4007                                       prevNod[i01], midlNod[i0],
4008                                       nextNod[i01], midlNod[i1],
4009                                       prevNod[i1a], prevNod[i0a],
4010                                       nextNod[i0a], nextNod[i1a]);
4011         }
4012         else if(nbSame==2) {
4013           // --->  2d order tetrahedron of 10 nodes
4014           int n1 = iNotSameNode;
4015           int n2 = ( n1 + 1             ) % nbCorners;
4016           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
4017           int n12 = n1 + 3;
4018           int n23 = n2 + 3;
4019           int n31 = n3 + 3;
4020           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
4021                                        prevNod[n12], prevNod[n23], prevNod[n31],
4022                                        midlNod[n1], nextNod[n12], nextNod[n31]);
4023         }
4024         break;
4025       }
4026       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
4027         if( nbSame == 0 ) {
4028           if ( nbDouble != 4 ) break;
4029           // --->  hexahedron with 20 nodes
4030           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
4031                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
4032                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
4033                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
4034                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
4035         }
4036         else if(nbSame==1) {
4037           // ---> pyramid + pentahedron - can not be created since it is needed
4038           // additional middle node at the center of face
4039           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
4040           return;
4041         }
4042         else if( nbSame == 2 ) {
4043           if ( nbDouble != 2 ) break;
4044           // --->  2d order Pentahedron with 15 nodes
4045           int n1,n2,n4,n5;
4046           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
4047             // iBeforeSame is same too
4048             n1 = iBeforeSame;
4049             n2 = iOpposSame;
4050             n4 = iSameNode;
4051             n5 = iAfterSame;
4052           }
4053           else {
4054             // iAfterSame is same too
4055             n1 = iSameNode;
4056             n2 = iBeforeSame;
4057             n4 = iAfterSame;
4058             n5 = iOpposSame;
4059           }
4060           int n12 = n2 + 4;
4061           int n45 = n4 + 4;
4062           int n14 = n1 + 4;
4063           int n25 = n5 + 4;
4064           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
4065                                        prevNod[n4], prevNod[n5], nextNod[n5],
4066                                        prevNod[n12], midlNod[n2], nextNod[n12],
4067                                        prevNod[n45], midlNod[n5], nextNod[n45],
4068                                        prevNod[n14], prevNod[n25], nextNod[n25]);
4069         }
4070         break;
4071       }
4072       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
4073
4074         if( nbSame == 0 && nbDouble == 9 ) {
4075           // --->  tri-quadratic hexahedron with 27 nodes
4076           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
4077                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
4078                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
4079                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
4080                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
4081                                        prevNod[8], // bottom center
4082                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
4083                                        nextNod[8], // top center
4084                                        midlNod[8]);// elem center
4085         }
4086         else
4087         {
4088           return;
4089         }
4090         break;
4091       }
4092       case SMDSEntity_Polygon: { // sweep POLYGON
4093
4094         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
4095           // --->  hexagonal prism
4096           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
4097                                        prevNod[3], prevNod[4], prevNod[5],
4098                                        nextNod[0], nextNod[1], nextNod[2],
4099                                        nextNod[3], nextNod[4], nextNod[5]);
4100         }
4101         break;
4102       }
4103       case SMDSEntity_Ball:
4104         return;
4105
4106       default:
4107         break;
4108       }
4109     }
4110
4111     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
4112     {
4113       if ( baseType != SMDSEntity_Polygon )
4114       {
4115         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
4116         SMDS_MeshCell::applyInterlace( ind, prevNod );
4117         SMDS_MeshCell::applyInterlace( ind, nextNod );
4118         SMDS_MeshCell::applyInterlace( ind, midlNod );
4119         SMDS_MeshCell::applyInterlace( ind, itNN );
4120         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
4121         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
4122       }
4123       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
4124       vector<int> quantities (nbNodes + 2);
4125       polyedre_nodes.clear();
4126       quantities.clear();
4127
4128       // bottom of prism
4129       for (int inode = 0; inode < nbNodes; inode++)
4130         polyedre_nodes.push_back( prevNod[inode] );
4131       quantities.push_back( nbNodes );
4132
4133       // top of prism
4134       polyedre_nodes.push_back( nextNod[0] );
4135       for (int inode = nbNodes; inode-1; --inode )
4136         polyedre_nodes.push_back( nextNod[inode-1] );
4137       quantities.push_back( nbNodes );
4138
4139       // side faces
4140       for (int iface = 0; iface < nbNodes; iface++)
4141       {
4142         const int prevNbNodes = polyedre_nodes.size();
4143         int inextface = (iface+1) % nbNodes;
4144         polyedre_nodes.push_back( prevNod[inextface] );
4145         polyedre_nodes.push_back( prevNod[iface] );
4146         if ( prevNod[iface] != nextNod[iface] )
4147         {
4148           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
4149           polyedre_nodes.push_back( nextNod[iface] );
4150         }
4151         if ( prevNod[inextface] != nextNod[inextface] )
4152         {
4153           polyedre_nodes.push_back( nextNod[inextface] );
4154           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
4155         }
4156         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
4157         if ( nbFaceNodes > 2 )
4158           quantities.push_back( nbFaceNodes );
4159         else // degenerated face
4160           polyedre_nodes.resize( prevNbNodes );
4161       }
4162       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
4163     }
4164
4165     if ( aNewElem ) {
4166       newElems.push_back( aNewElem );
4167       myLastCreatedElems.Append(aNewElem);
4168       srcElements.Append( elem );
4169     }
4170
4171     // set new prev nodes
4172     for ( iNode = 0; iNode < nbNodes; iNode++ )
4173       prevNod[ iNode ] = nextNod[ iNode ];
4174
4175   } // for steps
4176 }
4177
4178 //=======================================================================
4179 /*!
4180  * \brief Create 1D and 2D elements around swept elements
4181  * \param mapNewNodes - source nodes and ones generated from them
4182  * \param newElemsMap - source elements and ones generated from them
4183  * \param elemNewNodesMap - nodes generated from each node of each element
4184  * \param elemSet - all swept elements
4185  * \param nbSteps - number of sweeping steps
4186  * \param srcElements - to append elem for each generated element
4187  */
4188 //=======================================================================
4189
4190 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
4191                                   TElemOfElemListMap &     newElemsMap,
4192                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
4193                                   TIDSortedElemSet&        elemSet,
4194                                   const int                nbSteps,
4195                                   SMESH_SequenceOfElemPtr& srcElements)
4196 {
4197   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
4198   SMESHDS_Mesh* aMesh = GetMeshDS();
4199
4200   // Find nodes belonging to only one initial element - sweep them into edges.
4201
4202   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
4203   for ( ; nList != mapNewNodes.end(); nList++ )
4204   {
4205     const SMDS_MeshNode* node =
4206       static_cast<const SMDS_MeshNode*>( nList->first );
4207     if ( newElemsMap.count( node ))
4208       continue; // node was extruded into edge
4209     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
4210     int nbInitElems = 0;
4211     const SMDS_MeshElement* el = 0;
4212     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
4213     while ( eIt->more() && nbInitElems < 2 ) {
4214       el = eIt->next();
4215       SMDSAbs_ElementType type = el->GetType();
4216       if ( type == SMDSAbs_Volume || type < highType ) continue;
4217       if ( type > highType ) {
4218         nbInitElems = 0;
4219         highType = type;
4220       }
4221       nbInitElems += elemSet.count(el);
4222     }
4223     if ( nbInitElems < 2 ) {
4224       bool NotCreateEdge = el && el->IsMediumNode(node);
4225       if(!NotCreateEdge) {
4226         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
4227         list<const SMDS_MeshElement*> newEdges;
4228         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
4229       }
4230     }
4231   }
4232
4233   // Make a ceiling for each element ie an equal element of last new nodes.
4234   // Find free links of faces - make edges and sweep them into faces.
4235
4236   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
4237   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
4238   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
4239   {
4240     const SMDS_MeshElement* elem = itElem->first;
4241     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
4242
4243     if(itElem->second.size()==0) continue;
4244
4245     const bool isQuadratic = elem->IsQuadratic();
4246
4247     if ( elem->GetType() == SMDSAbs_Edge ) {
4248       // create a ceiling edge
4249       if ( !isQuadratic ) {
4250         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4251                                vecNewNodes[ 1 ]->second.back())) {
4252           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4253                                                    vecNewNodes[ 1 ]->second.back()));
4254           srcElements.Append( elem );
4255         }
4256       }
4257       else {
4258         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4259                                vecNewNodes[ 1 ]->second.back(),
4260                                vecNewNodes[ 2 ]->second.back())) {
4261           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4262                                                    vecNewNodes[ 1 ]->second.back(),
4263                                                    vecNewNodes[ 2 ]->second.back()));
4264           srcElements.Append( elem );
4265         }
4266       }
4267     }
4268     if ( elem->GetType() != SMDSAbs_Face )
4269       continue;
4270
4271     bool hasFreeLinks = false;
4272
4273     TIDSortedElemSet avoidSet;
4274     avoidSet.insert( elem );
4275
4276     set<const SMDS_MeshNode*> aFaceLastNodes;
4277     int iNode, nbNodes = vecNewNodes.size();
4278     if ( !isQuadratic ) {
4279       // loop on the face nodes
4280       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4281         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4282         // look for free links of the face
4283         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4284         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4285         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4286         // check if a link n1-n2 is free
4287         if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4288           hasFreeLinks = true;
4289           // make a new edge and a ceiling for a new edge
4290           const SMDS_MeshElement* edge;
4291           if ( ! ( edge = aMesh->FindEdge( n1, n2 ))) {
4292             myLastCreatedElems.Append( edge = aMesh->AddEdge( n1, n2 )); // free link edge
4293             srcElements.Append( myLastCreatedElems.Last() );
4294           }
4295           n1 = vecNewNodes[ iNode ]->second.back();
4296           n2 = vecNewNodes[ iNext ]->second.back();
4297           if ( !aMesh->FindEdge( n1, n2 )) {
4298             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling
4299             srcElements.Append( edge );
4300           }
4301         }
4302       }
4303     }
4304     else { // elem is quadratic face
4305       int nbn = nbNodes/2;
4306       for ( iNode = 0; iNode < nbn; iNode++ ) {
4307         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4308         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4309         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4310         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4311         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4312         // check if a link is free
4313         if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4314              ! SMESH_MeshAlgos::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4315              ! SMESH_MeshAlgos::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4316           hasFreeLinks = true;
4317           // make an edge and a ceiling for a new edge
4318           // find medium node
4319           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4320             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4321             srcElements.Append( elem );
4322           }
4323           n1 = vecNewNodes[ iNode ]->second.back();
4324           n2 = vecNewNodes[ iNext ]->second.back();
4325           n3 = vecNewNodes[ iNode+nbn ]->second.back();
4326           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4327             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4328             srcElements.Append( elem );
4329           }
4330         }
4331       }
4332       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4333         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4334       }
4335     }
4336
4337     // sweep free links into faces
4338
4339     if ( hasFreeLinks )  {
4340       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4341       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4342
4343       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4344       set<const SMDS_MeshNode*> initNodeSetNoCenter/*, topNodeSetNoCenter*/;
4345       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4346         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4347         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4348       }
4349       if ( isQuadratic && nbNodes % 2 ) {  // node set for the case of a biquadratic
4350         initNodeSetNoCenter = initNodeSet; // swept face and a not biquadratic volume
4351         initNodeSetNoCenter.erase( vecNewNodes.back()->first );
4352       }
4353       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4354         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4355         std::advance( v, volNb );
4356         // find indices of free faces of a volume and their source edges
4357         list< int > freeInd;
4358         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4359         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4360         int iF, nbF = vTool.NbFaces();
4361         for ( iF = 0; iF < nbF; iF ++ ) {
4362           if (vTool.IsFreeFace( iF ) &&
4363               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4364               initNodeSet != faceNodeSet) // except an initial face
4365           {
4366             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4367               continue;
4368             if ( faceNodeSet == initNodeSetNoCenter )
4369               continue;
4370             freeInd.push_back( iF );
4371             // find source edge of a free face iF
4372             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4373             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4374             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4375                                    initNodeSet.begin(), initNodeSet.end(),
4376                                    commonNodes.begin());
4377             if ( (*v)->IsQuadratic() )
4378               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4379             else
4380               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4381 #ifdef _DEBUG_
4382             if ( !srcEdges.back() )
4383             {
4384               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4385                    << iF << " of volume #" << vTool.ID() << endl;
4386             }
4387 #endif
4388           }
4389         }
4390         if ( freeInd.empty() )
4391           continue;
4392
4393         // create faces for all steps;
4394         // if such a face has been already created by sweep of edge,
4395         // assure that its orientation is OK
4396         for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4397           vTool.Set( *v, /*ignoreCentralNodes=*/false );
4398           vTool.SetExternalNormal();
4399           const int nextShift = vTool.IsForward() ? +1 : -1;
4400           list< int >::iterator ind = freeInd.begin();
4401           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4402           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4403           {
4404             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4405             int nbn = vTool.NbFaceNodes( *ind );
4406             const SMDS_MeshElement * f = 0;
4407             if ( nbn == 3 )              ///// triangle
4408             {
4409               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4410               if ( !f ||
4411                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4412               {
4413                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4414                                                      nodes[ 1 ],
4415                                                      nodes[ 1 + nextShift ] };
4416                 if ( f )
4417                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4418                 else
4419                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4420                                                             newOrder[ 2 ] ));
4421               }
4422             }
4423             else if ( nbn == 4 )       ///// quadrangle
4424             {
4425               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4426               if ( !f ||
4427                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4428               {
4429                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4430                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
4431                 if ( f )
4432                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4433                 else
4434                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4435                                                             newOrder[ 2 ], newOrder[ 3 ]));
4436               }
4437             }
4438             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4439             {
4440               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4441               if ( !f ||
4442                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4443               {
4444                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4445                                                      nodes[2],
4446                                                      nodes[2 + 2*nextShift],
4447                                                      nodes[3 - 2*nextShift],
4448                                                      nodes[3],
4449                                                      nodes[3 + 2*nextShift]};
4450                 if ( f )
4451                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4452                 else
4453                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4454                                                             newOrder[ 1 ],
4455                                                             newOrder[ 2 ],
4456                                                             newOrder[ 3 ],
4457                                                             newOrder[ 4 ],
4458                                                             newOrder[ 5 ] ));
4459               }
4460             }
4461             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4462             {
4463               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4464                                    nodes[1], nodes[3], nodes[5], nodes[7] );
4465               if ( !f ||
4466                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4467               {
4468                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4469                                                      nodes[4 - 2*nextShift],
4470                                                      nodes[4],
4471                                                      nodes[4 + 2*nextShift],
4472                                                      nodes[1],
4473                                                      nodes[5 - 2*nextShift],
4474                                                      nodes[5],
4475                                                      nodes[5 + 2*nextShift] };
4476                 if ( f )
4477                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4478                 else
4479                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4480                                                            newOrder[ 2 ], newOrder[ 3 ],
4481                                                            newOrder[ 4 ], newOrder[ 5 ],
4482                                                            newOrder[ 6 ], newOrder[ 7 ]));
4483               }
4484             }
4485             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4486             {
4487               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4488                                       SMDSAbs_Face, /*noMedium=*/false);
4489               if ( !f ||
4490                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4491               {
4492                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
4493                                                      nodes[4 - 2*nextShift],
4494                                                      nodes[4],
4495                                                      nodes[4 + 2*nextShift],
4496                                                      nodes[1],
4497                                                      nodes[5 - 2*nextShift],
4498                                                      nodes[5],
4499                                                      nodes[5 + 2*nextShift],
4500                                                      nodes[8] };
4501                 if ( f )
4502                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4503                 else
4504                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4505                                                            newOrder[ 2 ], newOrder[ 3 ],
4506                                                            newOrder[ 4 ], newOrder[ 5 ],
4507                                                            newOrder[ 6 ], newOrder[ 7 ],
4508                                                            newOrder[ 8 ]));
4509               }
4510             }
4511             else  //////// polygon
4512             {
4513               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
4514               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4515               if ( !f ||
4516                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4517               {
4518                 if ( !vTool.IsForward() )
4519                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4520                 if ( f )
4521                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4522                 else
4523                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4524               }
4525             }
4526
4527             while ( srcElements.Length() < myLastCreatedElems.Length() )
4528               srcElements.Append( *srcEdge );
4529
4530           }  // loop on free faces
4531
4532           // go to the next volume
4533           iVol = 0;
4534           while ( iVol++ < nbVolumesByStep ) v++;
4535
4536         } // loop on steps
4537       } // loop on volumes of one step
4538     } // sweep free links into faces
4539
4540     // Make a ceiling face with a normal external to a volume
4541
4542     // use SMDS_VolumeTool to get a correctly ordered nodes of a ceiling face
4543     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
4544     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4545
4546     if ( iF < 0 && isQuadratic && nbNodes % 2 ) { // remove a central node of biquadratic
4547       aFaceLastNodes.erase( vecNewNodes.back()->second.back() );
4548       iF = lastVol.GetFaceIndex( aFaceLastNodes );
4549     }
4550     if ( iF >= 0 ) {
4551       lastVol.SetExternalNormal();
4552       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4553       int nbn = lastVol.NbFaceNodes( iF );
4554       // we do not use this->AddElement() because nodes are interlaced
4555       vector<const SMDS_MeshNode*> nodeVec( nodes, nodes+nbn );
4556       if ( !hasFreeLinks ||
4557            !aMesh->FindElement( nodeVec, SMDSAbs_Face, /*noMedium=*/false) )
4558       {
4559         if ( nbn == 3 )
4560           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2] ));
4561
4562         else if ( nbn == 4 )
4563           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2], nodes[3]));
4564
4565         else if ( nbn == 6 && isQuadratic )
4566           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4],
4567                                                     nodes[1], nodes[3], nodes[5]));
4568         else if ( nbn == 7 && isQuadratic )
4569           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4],
4570                                                     nodes[1], nodes[3], nodes[5], nodes[6]));
4571         else if ( nbn == 8 && isQuadratic )
4572           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], nodes[6],
4573                                                     nodes[1], nodes[3], nodes[5], nodes[7]));
4574         else if ( nbn == 9 && isQuadratic )
4575           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], nodes[6],
4576                                                     nodes[1], nodes[3], nodes[5], nodes[7],
4577                                                     nodes[8]));
4578         else
4579           myLastCreatedElems.Append(aMesh->AddPolygonalFace( nodeVec ));
4580
4581         while ( srcElements.Length() < myLastCreatedElems.Length() )
4582           srcElements.Append( elem );
4583       }
4584     }
4585   } // loop on swept elements
4586 }
4587
4588 //=======================================================================
4589 //function : RotationSweep
4590 //purpose  :
4591 //=======================================================================
4592
4593 SMESH_MeshEditor::PGroupIDs
4594 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4595                                 const gp_Ax1&      theAxis,
4596                                 const double       theAngle,
4597                                 const int          theNbSteps,
4598                                 const double       theTol,
4599                                 const bool         theMakeGroups,
4600                                 const bool         theMakeWalls)
4601 {
4602   myLastCreatedElems.Clear();
4603   myLastCreatedNodes.Clear();
4604
4605   // source elements for each generated one
4606   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4607
4608   MESSAGE( "RotationSweep()");
4609   gp_Trsf aTrsf;
4610   aTrsf.SetRotation( theAxis, theAngle );
4611   gp_Trsf aTrsf2;
4612   aTrsf2.SetRotation( theAxis, theAngle/2. );
4613
4614   gp_Lin aLine( theAxis );
4615   double aSqTol = theTol * theTol;
4616
4617   SMESHDS_Mesh* aMesh = GetMeshDS();
4618
4619   TNodeOfNodeListMap mapNewNodes;
4620   TElemOfVecOfNnlmiMap mapElemNewNodes;
4621   TElemOfElemListMap newElemsMap;
4622
4623   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4624                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4625                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4626   // loop on theElems
4627   TIDSortedElemSet::iterator itElem;
4628   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4629     const SMDS_MeshElement* elem = *itElem;
4630     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4631       continue;
4632     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4633     newNodesItVec.reserve( elem->NbNodes() );
4634
4635     // loop on elem nodes
4636     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4637     while ( itN->more() )
4638     {
4639       // check if a node has been already sweeped
4640       const SMDS_MeshNode* node = cast2Node( itN->next() );
4641
4642       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4643       double coord[3];
4644       aXYZ.Coord( coord[0], coord[1], coord[2] );
4645       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4646
4647       TNodeOfNodeListMapItr nIt =
4648         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4649       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4650       if ( listNewNodes.empty() )
4651       {
4652         // check if we are to create medium nodes between corner ones
4653         bool needMediumNodes = false;
4654         if ( isQuadraticMesh )
4655         {
4656           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4657           while (it->more() && !needMediumNodes )
4658           {
4659             const SMDS_MeshElement* invElem = it->next();
4660             if ( invElem != elem && !theElems.count( invElem )) continue;
4661             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4662             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4663               needMediumNodes = true;
4664           }
4665         }
4666
4667         // make new nodes
4668         const SMDS_MeshNode * newNode = node;
4669         for ( int i = 0; i < theNbSteps; i++ ) {
4670           if ( !isOnAxis ) {
4671             if ( needMediumNodes )  // create a medium node
4672             {
4673               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4674               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4675               myLastCreatedNodes.Append(newNode);
4676               srcNodes.Append( node );
4677               listNewNodes.push_back( newNode );
4678               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4679             }
4680             else {
4681               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4682             }
4683             // create a corner node
4684             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4685             myLastCreatedNodes.Append(newNode);
4686             srcNodes.Append( node );
4687             listNewNodes.push_back( newNode );
4688           }
4689           else {
4690             listNewNodes.push_back( newNode );
4691             // if ( needMediumNodes )
4692             //   listNewNodes.push_back( newNode );
4693           }
4694         }
4695       }
4696       newNodesItVec.push_back( nIt );
4697     }
4698     // make new elements
4699     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4700   }
4701
4702   if ( theMakeWalls )
4703     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4704
4705   PGroupIDs newGroupIDs;
4706   if ( theMakeGroups )
4707     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4708
4709   return newGroupIDs;
4710 }
4711
4712
4713 //=======================================================================
4714 //function : CreateNode
4715 //purpose  :
4716 //=======================================================================
4717 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4718                                                   const double y,
4719                                                   const double z,
4720                                                   const double tolnode,
4721                                                   SMESH_SequenceOfNode& aNodes)
4722 {
4723   // myLastCreatedElems.Clear();
4724   // myLastCreatedNodes.Clear();
4725
4726   gp_Pnt P1(x,y,z);
4727   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4728
4729   // try to search in sequence of existing nodes
4730   // if aNodes.Length()>0 we 'nave to use given sequence
4731   // else - use all nodes of mesh
4732   if(aNodes.Length()>0) {
4733     int i;
4734     for(i=1; i<=aNodes.Length(); i++) {
4735       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4736       if(P1.Distance(P2)<tolnode)
4737         return aNodes.Value(i);
4738     }
4739   }
4740   else {
4741     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4742     while(itn->more()) {
4743       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4744       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4745       if(P1.Distance(P2)<tolnode)
4746         return aN;
4747     }
4748   }
4749
4750   // create new node and return it
4751   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4752   //myLastCreatedNodes.Append(NewNode);
4753   return NewNode;
4754 }
4755
4756
4757 //=======================================================================
4758 //function : ExtrusionSweep
4759 //purpose  :
4760 //=======================================================================
4761
4762 SMESH_MeshEditor::PGroupIDs
4763 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4764                                   const gp_Vec&       theStep,
4765                                   const int           theNbSteps,
4766                                   TElemOfElemListMap& newElemsMap,
4767                                   const bool          theMakeGroups,
4768                                   const int           theFlags,
4769                                   const double        theTolerance)
4770 {
4771   ExtrusParam aParams;
4772   aParams.myDir = gp_Dir(theStep);
4773   aParams.myNodes.Clear();
4774   aParams.mySteps = new TColStd_HSequenceOfReal;
4775   int i;
4776   for(i=1; i<=theNbSteps; i++)
4777     aParams.mySteps->Append(theStep.Magnitude());
4778
4779   return
4780     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4781 }
4782
4783
4784 //=======================================================================
4785 //function : ExtrusionSweep
4786 //purpose  :
4787 //=======================================================================
4788
4789 SMESH_MeshEditor::PGroupIDs
4790 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4791                                   ExtrusParam&        theParams,
4792                                   TElemOfElemListMap& newElemsMap,
4793                                   const bool          theMakeGroups,
4794                                   const int           theFlags,
4795                                   const double        theTolerance)
4796 {
4797   myLastCreatedElems.Clear();
4798   myLastCreatedNodes.Clear();
4799
4800   // source elements for each generated one
4801   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4802
4803   SMESHDS_Mesh* aMesh = GetMeshDS();
4804
4805   int nbsteps = theParams.mySteps->Length();
4806
4807   TNodeOfNodeListMap mapNewNodes;
4808   //TNodeOfNodeVecMap mapNewNodes;
4809   TElemOfVecOfNnlmiMap mapElemNewNodes;
4810   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4811
4812   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4813                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4814                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4815   // loop on theElems
4816   TIDSortedElemSet::iterator itElem;
4817   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4818     // check element type
4819     const SMDS_MeshElement* elem = *itElem;
4820     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4821       continue;
4822
4823     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4824     newNodesItVec.reserve( elem->NbNodes() );
4825
4826     // loop on elem nodes
4827     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4828     while ( itN->more() )
4829     {
4830       // check if a node has been already sweeped
4831       const SMDS_MeshNode* node = cast2Node( itN->next() );
4832       TNodeOfNodeListMap::iterator nIt =
4833         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4834       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4835       if ( listNewNodes.empty() )
4836       {
4837         // make new nodes
4838
4839         // check if we are to create medium nodes between corner ones
4840         bool needMediumNodes = false;
4841         if ( isQuadraticMesh )
4842         {
4843           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4844           while (it->more() && !needMediumNodes )
4845           {
4846             const SMDS_MeshElement* invElem = it->next();
4847             if ( invElem != elem && !theElems.count( invElem )) continue;
4848             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4849             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4850               needMediumNodes = true;
4851           }
4852         }
4853
4854         double coord[] = { node->X(), node->Y(), node->Z() };
4855         for ( int i = 0; i < nbsteps; i++ )
4856         {
4857           if ( needMediumNodes ) // create a medium node
4858           {
4859             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4860             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4861             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4862             if( theFlags & EXTRUSION_FLAG_SEW ) {
4863               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4864                                                          theTolerance, theParams.myNodes);
4865               listNewNodes.push_back( newNode );
4866             }
4867             else {
4868               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4869               myLastCreatedNodes.Append(newNode);
4870               srcNodes.Append( node );
4871               listNewNodes.push_back( newNode );
4872             }
4873           }
4874           // create a corner node
4875           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4876           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4877           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4878           if( theFlags & EXTRUSION_FLAG_SEW ) {
4879             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4880                                                        theTolerance, theParams.myNodes);
4881             listNewNodes.push_back( newNode );
4882           }
4883           else {
4884             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4885             myLastCreatedNodes.Append(newNode);
4886             srcNodes.Append( node );
4887             listNewNodes.push_back( newNode );
4888           }
4889         }
4890       }
4891       newNodesItVec.push_back( nIt );
4892     }
4893     // make new elements
4894     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4895   }
4896
4897   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4898     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4899   }
4900   PGroupIDs newGroupIDs;
4901   if ( theMakeGroups )
4902     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4903
4904   return newGroupIDs;
4905 }
4906
4907 //=======================================================================
4908 //function : ExtrusionAlongTrack
4909 //purpose  :
4910 //=======================================================================
4911 SMESH_MeshEditor::Extrusion_Error
4912 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4913                                        SMESH_subMesh*       theTrack,
4914                                        const SMDS_MeshNode* theN1,
4915                                        const bool           theHasAngles,
4916                                        list<double>&        theAngles,
4917                                        const bool           theLinearVariation,
4918                                        const bool           theHasRefPoint,
4919                                        const gp_Pnt&        theRefPoint,
4920                                        const bool           theMakeGroups)
4921 {
4922   MESSAGE("ExtrusionAlongTrack");
4923   myLastCreatedElems.Clear();
4924   myLastCreatedNodes.Clear();
4925
4926   int aNbE;
4927   std::list<double> aPrms;
4928   TIDSortedElemSet::iterator itElem;
4929
4930   gp_XYZ aGC;
4931   TopoDS_Edge aTrackEdge;
4932   TopoDS_Vertex aV1, aV2;
4933
4934   SMDS_ElemIteratorPtr aItE;
4935   SMDS_NodeIteratorPtr aItN;
4936   SMDSAbs_ElementType aTypeE;
4937
4938   TNodeOfNodeListMap mapNewNodes;
4939
4940   // 1. Check data
4941   aNbE = theElements.size();
4942   // nothing to do
4943   if ( !aNbE )
4944     return EXTR_NO_ELEMENTS;
4945
4946   // 1.1 Track Pattern
4947   ASSERT( theTrack );
4948
4949   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4950
4951   aItE = pSubMeshDS->GetElements();
4952   while ( aItE->more() ) {
4953     const SMDS_MeshElement* pE = aItE->next();
4954     aTypeE = pE->GetType();
4955     // Pattern must contain links only
4956     if ( aTypeE != SMDSAbs_Edge )
4957       return EXTR_PATH_NOT_EDGE;
4958   }
4959
4960   list<SMESH_MeshEditor_PathPoint> fullList;
4961
4962   const TopoDS_Shape& aS = theTrack->GetSubShape();
4963   // Sub-shape for the Pattern must be an Edge or Wire
4964   if( aS.ShapeType() == TopAbs_EDGE ) {
4965     aTrackEdge = TopoDS::Edge( aS );
4966     // the Edge must not be degenerated
4967     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4968       return EXTR_BAD_PATH_SHAPE;
4969     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4970     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4971     const SMDS_MeshNode* aN1 = aItN->next();
4972     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4973     const SMDS_MeshNode* aN2 = aItN->next();
4974     // starting node must be aN1 or aN2
4975     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4976       return EXTR_BAD_STARTING_NODE;
4977     aItN = pSubMeshDS->GetNodes();
4978     while ( aItN->more() ) {
4979       const SMDS_MeshNode* pNode = aItN->next();
4980       const SMDS_EdgePosition* pEPos =
4981         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4982       double aT = pEPos->GetUParameter();
4983       aPrms.push_back( aT );
4984     }
4985     //Extrusion_Error err =
4986     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4987   } else if( aS.ShapeType() == TopAbs_WIRE ) {
4988     list< SMESH_subMesh* > LSM;
4989     TopTools_SequenceOfShape Edges;
4990     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4991     while(itSM->more()) {
4992       SMESH_subMesh* SM = itSM->next();
4993       LSM.push_back(SM);
4994       const TopoDS_Shape& aS = SM->GetSubShape();
4995       Edges.Append(aS);
4996     }
4997     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4998     int startNid = theN1->GetID();
4999     TColStd_MapOfInteger UsedNums;
5000
5001     int NbEdges = Edges.Length();
5002     int i = 1;
5003     for(; i<=NbEdges; i++) {
5004       int k = 0;
5005       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5006       for(; itLSM!=LSM.end(); itLSM++) {
5007         k++;
5008         if(UsedNums.Contains(k)) continue;
5009         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5010         SMESH_subMesh* locTrack = *itLSM;
5011         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5012         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5013         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5014         const SMDS_MeshNode* aN1 = aItN->next();
5015         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5016         const SMDS_MeshNode* aN2 = aItN->next();
5017         // starting node must be aN1 or aN2
5018         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
5019         // 2. Collect parameters on the track edge
5020         aPrms.clear();
5021         aItN = locMeshDS->GetNodes();
5022         while ( aItN->more() ) {
5023           const SMDS_MeshNode* pNode = aItN->next();
5024           const SMDS_EdgePosition* pEPos =
5025             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5026           double aT = pEPos->GetUParameter();
5027           aPrms.push_back( aT );
5028         }
5029         list<SMESH_MeshEditor_PathPoint> LPP;
5030         //Extrusion_Error err =
5031         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
5032         LLPPs.push_back(LPP);
5033         UsedNums.Add(k);
5034         // update startN for search following egde
5035         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
5036         else startNid = aN1->GetID();
5037         break;
5038       }
5039     }
5040     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5041     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5042     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5043     for(; itPP!=firstList.end(); itPP++) {
5044       fullList.push_back( *itPP );
5045     }
5046     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5047     fullList.pop_back();
5048     itLLPP++;
5049     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5050       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5051       itPP = currList.begin();
5052       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5053       gp_Dir D1 = PP1.Tangent();
5054       gp_Dir D2 = PP2.Tangent();
5055       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5056                            (D1.Z()+D2.Z())/2 ) );
5057       PP1.SetTangent(Dnew);
5058       fullList.push_back(PP1);
5059       itPP++;
5060       for(; itPP!=firstList.end(); itPP++) {
5061         fullList.push_back( *itPP );
5062       }
5063       PP1 = fullList.back();
5064       fullList.pop_back();
5065     }
5066     // if wire not closed
5067     fullList.push_back(PP1);
5068     // else ???
5069   }
5070   else {
5071     return EXTR_BAD_PATH_SHAPE;
5072   }
5073
5074   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5075                           theHasRefPoint, theRefPoint, theMakeGroups);
5076 }
5077
5078
5079 //=======================================================================
5080 //function : ExtrusionAlongTrack
5081 //purpose  :
5082 //=======================================================================
5083 SMESH_MeshEditor::Extrusion_Error
5084 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
5085                                        SMESH_Mesh*          theTrack,
5086                                        const SMDS_MeshNode* theN1,
5087                                        const bool           theHasAngles,
5088                                        list<double>&        theAngles,
5089                                        const bool           theLinearVariation,
5090                                        const bool           theHasRefPoint,
5091                                        const gp_Pnt&        theRefPoint,
5092                                        const bool           theMakeGroups)
5093 {
5094   myLastCreatedElems.Clear();
5095   myLastCreatedNodes.Clear();
5096
5097   int aNbE;
5098   std::list<double> aPrms;
5099   TIDSortedElemSet::iterator itElem;
5100
5101   gp_XYZ aGC;
5102   TopoDS_Edge aTrackEdge;
5103   TopoDS_Vertex aV1, aV2;
5104
5105   SMDS_ElemIteratorPtr aItE;
5106   SMDS_NodeIteratorPtr aItN;
5107   SMDSAbs_ElementType aTypeE;
5108
5109   TNodeOfNodeListMap mapNewNodes;
5110
5111   // 1. Check data
5112   aNbE = theElements.size();
5113   // nothing to do
5114   if ( !aNbE )
5115     return EXTR_NO_ELEMENTS;
5116
5117   // 1.1 Track Pattern
5118   ASSERT( theTrack );
5119
5120   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
5121
5122   aItE = pMeshDS->elementsIterator();
5123   while ( aItE->more() ) {
5124     const SMDS_MeshElement* pE = aItE->next();
5125     aTypeE = pE->GetType();
5126     // Pattern must contain links only
5127     if ( aTypeE != SMDSAbs_Edge )
5128       return EXTR_PATH_NOT_EDGE;
5129   }
5130
5131   list<SMESH_MeshEditor_PathPoint> fullList;
5132
5133   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
5134
5135   if( aS == SMESH_Mesh::PseudoShape() ) {
5136     //Mesh without shape
5137     const SMDS_MeshNode* currentNode = NULL;
5138     const SMDS_MeshNode* prevNode = theN1;
5139     std::vector<const SMDS_MeshNode*> aNodesList;
5140     aNodesList.push_back(theN1);
5141     int nbEdges = 0, conn=0;
5142     const SMDS_MeshElement* prevElem = NULL;
5143     const SMDS_MeshElement* currentElem = NULL;
5144     int totalNbEdges = theTrack->NbEdges();
5145     SMDS_ElemIteratorPtr nIt;
5146
5147     //check start node
5148     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
5149       return EXTR_BAD_STARTING_NODE;
5150     }
5151
5152     conn = nbEdgeConnectivity(theN1);
5153     if(conn > 2)
5154       return EXTR_PATH_NOT_EDGE;
5155
5156     aItE = theN1->GetInverseElementIterator();
5157     prevElem = aItE->next();
5158     currentElem = prevElem;
5159     //Get all nodes
5160     if(totalNbEdges == 1 ) {
5161       nIt = currentElem->nodesIterator();
5162       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5163       if(currentNode == prevNode)
5164         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5165       aNodesList.push_back(currentNode);
5166     } else {
5167       nIt = currentElem->nodesIterator();
5168       while( nIt->more() ) {
5169         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5170         if(currentNode == prevNode)
5171           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5172         aNodesList.push_back(currentNode);
5173
5174         //case of the closed mesh
5175         if(currentNode == theN1) {
5176           nbEdges++;
5177           break;
5178         }
5179
5180         conn = nbEdgeConnectivity(currentNode);
5181         if(conn > 2) {
5182           return EXTR_PATH_NOT_EDGE;
5183         }else if( conn == 1 && nbEdges > 0 ) {
5184           //End of the path
5185           nbEdges++;
5186           break;
5187         }else {
5188           prevNode = currentNode;
5189           aItE = currentNode->GetInverseElementIterator();
5190           currentElem = aItE->next();
5191           if( currentElem  == prevElem)
5192             currentElem = aItE->next();
5193           nIt = currentElem->nodesIterator();
5194           prevElem = currentElem;
5195           nbEdges++;
5196         }
5197       }
5198     }
5199
5200     if(nbEdges != totalNbEdges)
5201       return EXTR_PATH_NOT_EDGE;
5202
5203     TopTools_SequenceOfShape Edges;
5204     double x1,x2,y1,y2,z1,z2;
5205     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5206     int startNid = theN1->GetID();
5207     for(int i = 1; i < aNodesList.size(); i++) {
5208       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
5209       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
5210       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
5211       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));
5212       list<SMESH_MeshEditor_PathPoint> LPP;
5213       aPrms.clear();
5214       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
5215       LLPPs.push_back(LPP);
5216       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
5217       else startNid = aNodesList[i-1]->GetID();
5218
5219     }
5220
5221     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5222     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5223     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5224     for(; itPP!=firstList.end(); itPP++) {
5225       fullList.push_back( *itPP );
5226     }
5227
5228     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5229     SMESH_MeshEditor_PathPoint PP2;
5230     fullList.pop_back();
5231     itLLPP++;
5232     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5233       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5234       itPP = currList.begin();
5235       PP2 = currList.front();
5236       gp_Dir D1 = PP1.Tangent();
5237       gp_Dir D2 = PP2.Tangent();
5238       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5239                            (D1.Z()+D2.Z())/2 ) );
5240       PP1.SetTangent(Dnew);
5241       fullList.push_back(PP1);
5242       itPP++;
5243       for(; itPP!=currList.end(); itPP++) {
5244         fullList.push_back( *itPP );
5245       }
5246       PP1 = fullList.back();
5247       fullList.pop_back();
5248     }
5249     fullList.push_back(PP1);
5250
5251   } // Sub-shape for the Pattern must be an Edge or Wire
5252   else if( aS.ShapeType() == TopAbs_EDGE ) {
5253     aTrackEdge = TopoDS::Edge( aS );
5254     // the Edge must not be degenerated
5255     if ( BRep_Tool::Degenerated( aTrackEdge ) )
5256       return EXTR_BAD_PATH_SHAPE;
5257     TopExp::Vertices( aTrackEdge, aV1, aV2 );
5258     const SMDS_MeshNode* aN1 = 0;
5259     const SMDS_MeshNode* aN2 = 0;
5260     if ( theTrack->GetSubMesh( aV1 ) && theTrack->GetSubMesh( aV1 )->GetSubMeshDS() ) {
5261       aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
5262       aN1 = aItN->next();
5263     }
5264     if ( theTrack->GetSubMesh( aV2 ) && theTrack->GetSubMesh( aV2 )->GetSubMeshDS() ) {
5265       aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
5266       aN2 = aItN->next();
5267     }
5268     // starting node must be aN1 or aN2
5269     if ( !( aN1 == theN1 || aN2 == theN1 ) )
5270       return EXTR_BAD_STARTING_NODE;
5271     aItN = pMeshDS->nodesIterator();
5272     while ( aItN->more() ) {
5273       const SMDS_MeshNode* pNode = aItN->next();
5274       if( pNode==aN1 || pNode==aN2 ) continue;
5275       const SMDS_EdgePosition* pEPos =
5276         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5277       double aT = pEPos->GetUParameter();
5278       aPrms.push_back( aT );
5279     }
5280     //Extrusion_Error err =
5281     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5282   }
5283   else if( aS.ShapeType() == TopAbs_WIRE ) {
5284     list< SMESH_subMesh* > LSM;
5285     TopTools_SequenceOfShape Edges;
5286     TopExp_Explorer eExp(aS, TopAbs_EDGE);
5287     for(; eExp.More(); eExp.Next()) {
5288       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5289       if( BRep_Tool::Degenerated(E) ) continue;
5290       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5291       if(SM) {
5292         LSM.push_back(SM);
5293         Edges.Append(E);
5294       }
5295     }
5296     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5297     TopoDS_Vertex aVprev;
5298     TColStd_MapOfInteger UsedNums;
5299     int NbEdges = Edges.Length();
5300     int i = 1;
5301     for(; i<=NbEdges; i++) {
5302       int k = 0;
5303       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5304       for(; itLSM!=LSM.end(); itLSM++) {
5305         k++;
5306         if(UsedNums.Contains(k)) continue;
5307         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5308         SMESH_subMesh* locTrack = *itLSM;
5309         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5310         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5311         bool aN1isOK = false, aN2isOK = false;
5312         if ( aVprev.IsNull() ) {
5313           // if previous vertex is not yet defined, it means that we in the beginning of wire
5314           // and we have to find initial vertex corresponding to starting node theN1
5315           const SMDS_MeshNode* aN1 = 0;
5316           const SMDS_MeshNode* aN2 = 0;
5317
5318           if ( locTrack->GetFather()->GetSubMesh(aV1) && locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS() ) {
5319             aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5320             aN1 = aItN->next();
5321           }
5322           if ( locTrack->GetFather()->GetSubMesh(aV2) && locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS() ) {
5323             aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5324             aN2 = aItN->next();
5325           }
5326           // starting node must be aN1 or aN2
5327           aN1isOK = ( aN1 && aN1 == theN1 );
5328           aN2isOK = ( aN2 && aN2 == theN1 );
5329         }
5330         else {
5331           // we have specified ending vertex of the previous edge on the previous iteration
5332           // and we have just to check that it corresponds to any vertex in current segment
5333           aN1isOK = aVprev.IsSame( aV1 );
5334           aN2isOK = aVprev.IsSame( aV2 );
5335         }
5336         if ( !aN1isOK && !aN2isOK ) continue;
5337         // 2. Collect parameters on the track edge
5338         aPrms.clear();
5339         aItN = locMeshDS->GetNodes();
5340         while ( aItN->more() ) {
5341           const SMDS_MeshNode*     pNode = aItN->next();
5342           const SMDS_EdgePosition* pEPos =
5343             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5344           double aT = pEPos->GetUParameter();
5345           aPrms.push_back( aT );
5346         }
5347         list<SMESH_MeshEditor_PathPoint> LPP;
5348         //Extrusion_Error err =
5349         MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
5350         LLPPs.push_back(LPP);
5351         UsedNums.Add(k);
5352         // update startN for search following egde
5353         if ( aN1isOK ) aVprev = aV2;
5354         else           aVprev = aV1;
5355         break;
5356       }
5357     }
5358     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5359     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5360     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5361     for(; itPP!=firstList.end(); itPP++) {
5362       fullList.push_back( *itPP );
5363     }
5364     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5365     fullList.pop_back();
5366     itLLPP++;
5367     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5368       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5369       itPP = currList.begin();
5370       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5371       gp_Dir D1 = PP1.Tangent();
5372       gp_Dir D2 = PP2.Tangent();
5373       gp_Dir Dnew( ( D1.XYZ() + D2.XYZ() ) / 2 );
5374       PP1.SetTangent(Dnew);
5375       fullList.push_back(PP1);
5376       itPP++;
5377       for(; itPP!=currList.end(); itPP++) {
5378         fullList.push_back( *itPP );
5379       }
5380       PP1 = fullList.back();
5381       fullList.pop_back();
5382     }
5383     // if wire not closed
5384     fullList.push_back(PP1);
5385     // else ???
5386   }
5387   else {
5388     return EXTR_BAD_PATH_SHAPE;
5389   }
5390
5391   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5392                           theHasRefPoint, theRefPoint, theMakeGroups);
5393 }
5394
5395
5396 //=======================================================================
5397 //function : MakeEdgePathPoints
5398 //purpose  : auxilary for ExtrusionAlongTrack
5399 //=======================================================================
5400 SMESH_MeshEditor::Extrusion_Error
5401 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5402                                      const TopoDS_Edge& aTrackEdge,
5403                                      bool FirstIsStart,
5404                                      list<SMESH_MeshEditor_PathPoint>& LPP)
5405 {
5406   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5407   aTolVec=1.e-7;
5408   aTolVec2=aTolVec*aTolVec;
5409   double aT1, aT2;
5410   TopoDS_Vertex aV1, aV2;
5411   TopExp::Vertices( aTrackEdge, aV1, aV2 );
5412   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5413   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5414   // 2. Collect parameters on the track edge
5415   aPrms.push_front( aT1 );
5416   aPrms.push_back( aT2 );
5417   // sort parameters
5418   aPrms.sort();
5419   if( FirstIsStart ) {
5420     if ( aT1 > aT2 ) {
5421       aPrms.reverse();
5422     }
5423   }
5424   else {
5425     if ( aT2 > aT1 ) {
5426       aPrms.reverse();
5427     }
5428   }
5429   // 3. Path Points
5430   SMESH_MeshEditor_PathPoint aPP;
5431   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5432   std::list<double>::iterator aItD = aPrms.begin();
5433   for(; aItD != aPrms.end(); ++aItD) {
5434     double aT = *aItD;
5435     gp_Pnt aP3D;
5436     gp_Vec aVec;
5437     aC3D->D1( aT, aP3D, aVec );
5438     aL2 = aVec.SquareMagnitude();
5439     if ( aL2 < aTolVec2 )
5440       return EXTR_CANT_GET_TANGENT;
5441     gp_Dir aTgt( aVec );
5442     aPP.SetPnt( aP3D );
5443     aPP.SetTangent( aTgt );
5444     aPP.SetParameter( aT );
5445     LPP.push_back(aPP);
5446   }
5447   return EXTR_OK;
5448 }
5449
5450
5451 //=======================================================================
5452 //function : MakeExtrElements
5453 //purpose  : auxilary for ExtrusionAlongTrack
5454 //=======================================================================
5455 SMESH_MeshEditor::Extrusion_Error
5456 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5457                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5458                                    const bool theHasAngles,
5459                                    list<double>& theAngles,
5460                                    const bool theLinearVariation,
5461                                    const bool theHasRefPoint,
5462                                    const gp_Pnt& theRefPoint,
5463                                    const bool theMakeGroups)
5464 {
5465   MESSAGE("MakeExtrElements");
5466   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5467   int aNbTP = fullList.size();
5468   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5469   // Angles
5470   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5471     LinearAngleVariation(aNbTP-1, theAngles);
5472   }
5473   vector<double> aAngles( aNbTP );
5474   int j = 0;
5475   for(; j<aNbTP; ++j) {
5476     aAngles[j] = 0.;
5477   }
5478   if ( theHasAngles ) {
5479     double anAngle;;
5480     std::list<double>::iterator aItD = theAngles.begin();
5481     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5482       anAngle = *aItD;
5483       aAngles[j] = anAngle;
5484     }
5485   }
5486   // fill vector of path points with angles
5487   //aPPs.resize(fullList.size());
5488   j = -1;
5489   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5490   for(; itPP!=fullList.end(); itPP++) {
5491     j++;
5492     SMESH_MeshEditor_PathPoint PP = *itPP;
5493     PP.SetAngle(aAngles[j]);
5494     aPPs[j] = PP;
5495   }
5496
5497   TNodeOfNodeListMap mapNewNodes;
5498   TElemOfVecOfNnlmiMap mapElemNewNodes;
5499   TElemOfElemListMap newElemsMap;
5500   TIDSortedElemSet::iterator itElem;
5501   double aX, aY, aZ;
5502   int aNb;
5503   SMDSAbs_ElementType aTypeE;
5504   // source elements for each generated one
5505   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5506
5507   // 3. Center of rotation aV0
5508   gp_Pnt aV0 = theRefPoint;
5509   gp_XYZ aGC;
5510   if ( !theHasRefPoint ) {
5511     aNb = 0;
5512     aGC.SetCoord( 0.,0.,0. );
5513
5514     itElem = theElements.begin();
5515     for ( ; itElem != theElements.end(); itElem++ ) {
5516       const SMDS_MeshElement* elem = *itElem;
5517
5518       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5519       while ( itN->more() ) {
5520         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5521         aX = node->X();
5522         aY = node->Y();
5523         aZ = node->Z();
5524
5525         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5526           list<const SMDS_MeshNode*> aLNx;
5527           mapNewNodes[node] = aLNx;
5528           //
5529           gp_XYZ aXYZ( aX, aY, aZ );
5530           aGC += aXYZ;
5531           ++aNb;
5532         }
5533       }
5534     }
5535     aGC /= aNb;
5536     aV0.SetXYZ( aGC );
5537   } // if (!theHasRefPoint) {
5538   mapNewNodes.clear();
5539
5540   // 4. Processing the elements
5541   SMESHDS_Mesh* aMesh = GetMeshDS();
5542
5543   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5544     // check element type
5545     const SMDS_MeshElement* elem = *itElem;
5546     aTypeE = elem->GetType();
5547     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5548       continue;
5549
5550     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5551     newNodesItVec.reserve( elem->NbNodes() );
5552
5553     // loop on elem nodes
5554     int nodeIndex = -1;
5555     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5556     while ( itN->more() )
5557     {
5558       ++nodeIndex;
5559       // check if a node has been already processed
5560       const SMDS_MeshNode* node =
5561         static_cast<const SMDS_MeshNode*>( itN->next() );
5562       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5563       if ( nIt == mapNewNodes.end() ) {
5564         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5565         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5566
5567         // make new nodes
5568         aX = node->X();  aY = node->Y(); aZ = node->Z();
5569
5570         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5571         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5572         gp_Ax1 anAx1, anAxT1T0;
5573         gp_Dir aDT1x, aDT0x, aDT1T0;
5574
5575         aTolAng=1.e-4;
5576
5577         aV0x = aV0;
5578         aPN0.SetCoord(aX, aY, aZ);
5579
5580         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5581         aP0x = aPP0.Pnt();
5582         aDT0x= aPP0.Tangent();
5583         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5584
5585         for ( j = 1; j < aNbTP; ++j ) {
5586           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5587           aP1x = aPP1.Pnt();
5588           aDT1x = aPP1.Tangent();
5589           aAngle1x = aPP1.Angle();
5590
5591           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5592           // Translation
5593           gp_Vec aV01x( aP0x, aP1x );
5594           aTrsf.SetTranslation( aV01x );
5595
5596           // traslated point
5597           aV1x = aV0x.Transformed( aTrsf );
5598           aPN1 = aPN0.Transformed( aTrsf );
5599
5600           // rotation 1 [ T1,T0 ]
5601           aAngleT1T0=-aDT1x.Angle( aDT0x );
5602           if (fabs(aAngleT1T0) > aTolAng) {
5603             aDT1T0=aDT1x^aDT0x;
5604             anAxT1T0.SetLocation( aV1x );
5605             anAxT1T0.SetDirection( aDT1T0 );
5606             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5607
5608             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5609           }
5610
5611           // rotation 2
5612           if ( theHasAngles ) {
5613             anAx1.SetLocation( aV1x );
5614             anAx1.SetDirection( aDT1x );
5615             aTrsfRot.SetRotation( anAx1, aAngle1x );
5616
5617             aPN1 = aPN1.Transformed( aTrsfRot );
5618           }
5619
5620           // make new node
5621           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5622           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5623             // create additional node
5624             double x = ( aPN1.X() + aPN0.X() )/2.;
5625             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5626             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5627             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5628             myLastCreatedNodes.Append(newNode);
5629             srcNodes.Append( node );
5630             listNewNodes.push_back( newNode );
5631           }
5632           aX = aPN1.X();
5633           aY = aPN1.Y();
5634           aZ = aPN1.Z();
5635           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5636           myLastCreatedNodes.Append(newNode);
5637           srcNodes.Append( node );
5638           listNewNodes.push_back( newNode );
5639
5640           aPN0 = aPN1;
5641           aP0x = aP1x;
5642           aV0x = aV1x;
5643           aDT0x = aDT1x;
5644         }
5645       }
5646
5647       else {
5648         // if current elem is quadratic and current node is not medium
5649         // we have to check - may be it is needed to insert additional nodes
5650         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5651           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5652           if(listNewNodes.size()==aNbTP-1) {
5653             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5654             gp_XYZ P(node->X(), node->Y(), node->Z());
5655             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5656             int i;
5657             for(i=0; i<aNbTP-1; i++) {
5658               const SMDS_MeshNode* N = *it;
5659               double x = ( N->X() + P.X() )/2.;
5660               double y = ( N->Y() + P.Y() )/2.;
5661               double z = ( N->Z() + P.Z() )/2.;
5662               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5663               srcNodes.Append( node );
5664               myLastCreatedNodes.Append(newN);
5665               aNodes[2*i] = newN;
5666               aNodes[2*i+1] = N;
5667               P = gp_XYZ(N->X(),N->Y(),N->Z());
5668             }
5669             listNewNodes.clear();
5670             for(i=0; i<2*(aNbTP-1); i++) {
5671               listNewNodes.push_back(aNodes[i]);
5672             }
5673           }
5674         }
5675       }
5676
5677       newNodesItVec.push_back( nIt );
5678     }
5679     // make new elements
5680     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5681     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5682     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5683   }
5684
5685   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5686
5687   if ( theMakeGroups )
5688     generateGroups( srcNodes, srcElems, "extruded");
5689
5690   return EXTR_OK;
5691 }
5692
5693
5694 //=======================================================================
5695 //function : LinearAngleVariation
5696 //purpose  : auxilary for ExtrusionAlongTrack
5697 //=======================================================================
5698 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5699                                             list<double>& Angles)
5700 {
5701   int nbAngles = Angles.size();
5702   if( nbSteps > nbAngles ) {
5703     vector<double> theAngles(nbAngles);
5704     list<double>::iterator it = Angles.begin();
5705     int i = -1;
5706     for(; it!=Angles.end(); it++) {
5707       i++;
5708       theAngles[i] = (*it);
5709     }
5710     list<double> res;
5711     double rAn2St = double( nbAngles ) / double( nbSteps );
5712     double angPrev = 0, angle;
5713     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5714       double angCur = rAn2St * ( iSt+1 );
5715       double angCurFloor  = floor( angCur );
5716       double angPrevFloor = floor( angPrev );
5717       if ( angPrevFloor == angCurFloor )
5718         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5719       else {
5720         int iP = int( angPrevFloor );
5721         double angPrevCeil = ceil(angPrev);
5722         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5723
5724         int iC = int( angCurFloor );
5725         if ( iC < nbAngles )
5726           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5727
5728         iP = int( angPrevCeil );
5729         while ( iC-- > iP )
5730           angle += theAngles[ iC ];
5731       }
5732       res.push_back(angle);
5733       angPrev = angCur;
5734     }
5735     Angles.clear();
5736     it = res.begin();
5737     for(; it!=res.end(); it++)
5738       Angles.push_back( *it );
5739   }
5740 }
5741
5742
5743 //================================================================================
5744 /*!
5745  * \brief Move or copy theElements applying theTrsf to their nodes
5746  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5747  *  \param theTrsf - transformation to apply
5748  *  \param theCopy - if true, create translated copies of theElems
5749  *  \param theMakeGroups - if true and theCopy, create translated groups
5750  *  \param theTargetMesh - mesh to copy translated elements into
5751  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5752  */
5753 //================================================================================
5754
5755 SMESH_MeshEditor::PGroupIDs
5756 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5757                              const gp_Trsf&     theTrsf,
5758                              const bool         theCopy,
5759                              const bool         theMakeGroups,
5760                              SMESH_Mesh*        theTargetMesh)
5761 {
5762   myLastCreatedElems.Clear();
5763   myLastCreatedNodes.Clear();
5764
5765   bool needReverse = false;
5766   string groupPostfix;
5767   switch ( theTrsf.Form() ) {
5768   case gp_PntMirror:
5769     MESSAGE("gp_PntMirror");
5770     needReverse = true;
5771     groupPostfix = "mirrored";
5772     break;
5773   case gp_Ax1Mirror:
5774     MESSAGE("gp_Ax1Mirror");
5775     groupPostfix = "mirrored";
5776     break;
5777   case gp_Ax2Mirror:
5778     MESSAGE("gp_Ax2Mirror");
5779     needReverse = true;
5780     groupPostfix = "mirrored";
5781     break;
5782   case gp_Rotation:
5783     MESSAGE("gp_Rotation");
5784     groupPostfix = "rotated";
5785     break;
5786   case gp_Translation:
5787     MESSAGE("gp_Translation");
5788     groupPostfix = "translated";
5789     break;
5790   case gp_Scale:
5791     MESSAGE("gp_Scale");
5792     groupPostfix = "scaled";
5793     break;
5794   case gp_CompoundTrsf: // different scale by axis
5795     MESSAGE("gp_CompoundTrsf");
5796     groupPostfix = "scaled";
5797     break;
5798   default:
5799     MESSAGE("default");
5800     needReverse = false;
5801     groupPostfix = "transformed";
5802   }
5803
5804   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5805   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5806   SMESHDS_Mesh* aMesh    = GetMeshDS();
5807
5808
5809   // map old node to new one
5810   TNodeNodeMap nodeMap;
5811
5812   // elements sharing moved nodes; those of them which have all
5813   // nodes mirrored but are not in theElems are to be reversed
5814   TIDSortedElemSet inverseElemSet;
5815
5816   // source elements for each generated one
5817   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5818
5819   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5820   TIDSortedElemSet orphanNode;
5821
5822   if ( theElems.empty() ) // transform the whole mesh
5823   {
5824     // add all elements
5825     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5826     while ( eIt->more() ) theElems.insert( eIt->next() );
5827     // add orphan nodes
5828     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5829     while ( nIt->more() )
5830     {
5831       const SMDS_MeshNode* node = nIt->next();
5832       if ( node->NbInverseElements() == 0)
5833         orphanNode.insert( node );
5834     }
5835   }
5836
5837   // loop on elements to transform nodes : first orphan nodes then elems
5838   TIDSortedElemSet::iterator itElem;
5839   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5840   for (int i=0; i<2; i++)
5841   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5842     const SMDS_MeshElement* elem = *itElem;
5843     if ( !elem )
5844       continue;
5845
5846     // loop on elem nodes
5847     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5848     while ( itN->more() ) {
5849
5850       const SMDS_MeshNode* node = cast2Node( itN->next() );
5851       // check if a node has been already transformed
5852       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5853         nodeMap.insert( make_pair ( node, node ));
5854       if ( !n2n_isnew.second )
5855         continue;
5856
5857       double coord[3];
5858       coord[0] = node->X();
5859       coord[1] = node->Y();
5860       coord[2] = node->Z();
5861       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5862       if ( theTargetMesh ) {
5863         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5864         n2n_isnew.first->second = newNode;
5865         myLastCreatedNodes.Append(newNode);
5866         srcNodes.Append( node );
5867       }
5868       else if ( theCopy ) {
5869         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5870         n2n_isnew.first->second = newNode;
5871         myLastCreatedNodes.Append(newNode);
5872         srcNodes.Append( node );
5873       }
5874       else {
5875         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5876         // node position on shape becomes invalid
5877         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5878           ( SMDS_SpacePosition::originSpacePosition() );
5879       }
5880
5881       // keep inverse elements
5882       if ( !theCopy && !theTargetMesh && needReverse ) {
5883         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5884         while ( invElemIt->more() ) {
5885           const SMDS_MeshElement* iel = invElemIt->next();
5886           inverseElemSet.insert( iel );
5887         }
5888       }
5889     }
5890   }
5891
5892   // either create new elements or reverse mirrored ones
5893   if ( !theCopy && !needReverse && !theTargetMesh )
5894     return PGroupIDs();
5895
5896   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5897   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5898     theElems.insert( *invElemIt );
5899
5900   // Replicate or reverse elements
5901
5902   std::vector<int> iForw;
5903   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5904   {
5905     const SMDS_MeshElement* elem = *itElem;
5906     if ( !elem ) continue;
5907
5908     SMDSAbs_GeometryType geomType = elem->GetGeomType();
5909     int                  nbNodes  = elem->NbNodes();
5910     if ( geomType == SMDSGeom_NONE ) continue; // node
5911
5912     switch ( geomType ) {
5913
5914     case SMDSGeom_POLYGON:  // ---------------------- polygon
5915       {
5916         vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5917         int iNode = 0;
5918         SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5919         while (itN->more()) {
5920           const SMDS_MeshNode* node =
5921             static_cast<const SMDS_MeshNode*>(itN->next());
5922           TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5923           if (nodeMapIt == nodeMap.end())
5924             break; // not all nodes transformed
5925           if (needReverse) {
5926             // reverse mirrored faces and volumes
5927             poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5928           } else {
5929             poly_nodes[iNode] = (*nodeMapIt).second;
5930           }
5931           iNode++;
5932         }
5933         if ( iNode != nbNodes )
5934           continue; // not all nodes transformed
5935
5936         if ( theTargetMesh ) {
5937           myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5938           srcElems.Append( elem );
5939         }
5940         else if ( theCopy ) {
5941           myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5942           srcElems.Append( elem );
5943         }
5944         else {
5945           aMesh->ChangePolygonNodes(elem, poly_nodes);
5946         }
5947       }
5948       break;
5949
5950     case SMDSGeom_POLYHEDRA:  // ------------------ polyhedral volume
5951       {
5952         const SMDS_VtkVolume* aPolyedre =
5953           dynamic_cast<const SMDS_VtkVolume*>( elem );
5954         if (!aPolyedre) {
5955           MESSAGE("Warning: bad volumic element");
5956           continue;
5957         }
5958
5959         vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
5960         vector<int> quantities; quantities.reserve( nbNodes );
5961
5962         bool allTransformed = true;
5963         int nbFaces = aPolyedre->NbFaces();
5964         for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5965           int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5966           for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5967             const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5968             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5969             if (nodeMapIt == nodeMap.end()) {
5970               allTransformed = false; // not all nodes transformed
5971             } else {
5972               poly_nodes.push_back((*nodeMapIt).second);
5973             }
5974             if ( needReverse && allTransformed )
5975               std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
5976           }
5977           quantities.push_back(nbFaceNodes);
5978         }
5979         if ( !allTransformed )
5980           continue; // not all nodes transformed
5981
5982         if ( theTargetMesh ) {
5983           myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5984           srcElems.Append( elem );
5985         }
5986         else if ( theCopy ) {
5987           myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5988           srcElems.Append( elem );
5989         }
5990         else {
5991           aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5992         }
5993       }
5994       break;
5995
5996     case SMDSGeom_BALL: // -------------------- Ball
5997       {
5998         if ( !theCopy && !theTargetMesh ) continue;
5999
6000         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) );
6001         if (nodeMapIt == nodeMap.end())
6002           continue; // not all nodes transformed
6003
6004         double diameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
6005         if ( theTargetMesh ) {
6006           myLastCreatedElems.Append(aTgtMesh->AddBall( nodeMapIt->second, diameter ));
6007           srcElems.Append( elem );
6008         }
6009         else {
6010           myLastCreatedElems.Append(aMesh->AddBall( nodeMapIt->second, diameter ));
6011           srcElems.Append( elem );
6012         }
6013       }
6014       break;
6015
6016     default: // ----------------------- Regular elements
6017
6018       while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
6019       const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
6020       const std::vector<int>& i = needReverse ? iRev : iForw;
6021
6022       // find transformed nodes
6023       vector<const SMDS_MeshNode*> nodes(nbNodes);
6024       int iNode = 0;
6025       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6026       while ( itN->more() ) {
6027         const SMDS_MeshNode* node =
6028           static_cast<const SMDS_MeshNode*>( itN->next() );
6029         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
6030         if ( nodeMapIt == nodeMap.end() )
6031           break; // not all nodes transformed
6032         nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
6033       }
6034       if ( iNode != nbNodes )
6035         continue; // not all nodes transformed
6036
6037       if ( theTargetMesh ) {
6038         if ( SMDS_MeshElement* copy =
6039              targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
6040           myLastCreatedElems.Append( copy );
6041           srcElems.Append( elem );
6042         }
6043       }
6044       else if ( theCopy ) {
6045         if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
6046           srcElems.Append( elem );
6047       }
6048       else {
6049         // reverse element as it was reversed by transformation
6050         if ( nbNodes > 2 )
6051           aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
6052       }
6053     } // switch ( geomType )
6054
6055   } // loop on elements
6056
6057   PGroupIDs newGroupIDs;
6058
6059   if ( ( theMakeGroups && theCopy ) ||
6060        ( theMakeGroups && theTargetMesh ) )
6061     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
6062
6063   return newGroupIDs;
6064 }
6065
6066 //=======================================================================
6067 /*!
6068  * \brief Create groups of elements made during transformation
6069  * \param nodeGens - nodes making corresponding myLastCreatedNodes
6070  * \param elemGens - elements making corresponding myLastCreatedElems
6071  * \param postfix - to append to names of new groups
6072  */
6073 //=======================================================================
6074
6075 SMESH_MeshEditor::PGroupIDs
6076 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
6077                                  const SMESH_SequenceOfElemPtr& elemGens,
6078                                  const std::string&             postfix,
6079                                  SMESH_Mesh*                    targetMesh)
6080 {
6081   PGroupIDs newGroupIDs( new list<int> );
6082   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6083
6084   // Sort existing groups by types and collect their names
6085
6086   // to store an old group and a generated new ones
6087   using boost::tuple;
6088   using boost::make_tuple;
6089   typedef tuple< SMESHDS_GroupBase*, SMESHDS_Group*, SMESHDS_Group* > TOldNewGroup;
6090   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6091   vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups
6092   // group names
6093   set< string > groupNames;
6094
6095   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6096   if ( !groupIt->more() ) return newGroupIDs;
6097
6098   int newGroupID = mesh->GetGroupIds().back()+1;
6099   while ( groupIt->more() )
6100   {
6101     SMESH_Group * group = groupIt->next();
6102     if ( !group ) continue;
6103     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6104     if ( !groupDS || groupDS->IsEmpty() ) continue;
6105     groupNames.insert    ( group->GetName() );
6106     groupDS->SetStoreName( group->GetName() );
6107     const SMDSAbs_ElementType type = groupDS->GetType();
6108     SMESHDS_Group* newGroup    = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
6109     SMESHDS_Group* newTopGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
6110     groupsByType[ type ].push_back( make_tuple( groupDS, newGroup, newTopGroup ));
6111     orderedOldNewGroups.push_back( & groupsByType[ type ].back() );
6112   }
6113
6114   // Loop on nodes and elements to add them in new groups
6115
6116   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6117   {
6118     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6119     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6120     if ( gens.Length() != elems.Length() )
6121       throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args");
6122
6123     // loop on created elements
6124     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6125     {
6126       const SMDS_MeshElement* sourceElem = gens( iElem );
6127       if ( !sourceElem ) {
6128         MESSAGE("generateGroups(): NULL source element");
6129         continue;
6130       }
6131       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6132       if ( groupsOldNew.empty() ) { // no groups of this type at all
6133         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6134           ++iElem; // skip all elements made by sourceElem
6135         continue;
6136       }
6137       // collect all elements made by the iElem-th sourceElem
6138       list< const SMDS_MeshElement* > resultElems;
6139       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6140         if ( resElem != sourceElem )
6141           resultElems.push_back( resElem );
6142       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6143         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6144           if ( resElem != sourceElem )
6145             resultElems.push_back( resElem );
6146
6147       // there must be a top element
6148       const SMDS_MeshElement* topElem = 0;
6149       if ( isNodes )
6150       {
6151         topElem = resultElems.back();
6152         resultElems.pop_back();
6153       }
6154       else
6155       {
6156         list< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin();
6157         for ( ; resElemIt != resultElems.rend() ; ++resElemIt )
6158           if ( (*resElemIt)->GetType() == sourceElem->GetType() )
6159           {
6160             topElem = *resElemIt;
6161             resultElems.erase( --(resElemIt.base()) ); // erase *resElemIt
6162             break;
6163           }
6164       }
6165
6166       // add resultElems to groups originted from ones the sourceElem belongs to
6167       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6168       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6169       {
6170         SMESHDS_GroupBase* oldGroup = gOldNew->get<0>();
6171         if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup
6172         {
6173           // fill in a new group
6174           SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup();
6175           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6176           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6177             newGroup.Add( *resElemIt );
6178
6179           // fill a "top" group
6180           if ( topElem )
6181           {
6182             SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup();
6183             newTopGroup.Add( topElem );
6184           }
6185         }
6186       }
6187     } // loop on created elements
6188   }// loop on nodes and elements
6189
6190   // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups
6191
6192   list<int> topGrouIds;
6193   for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i )
6194   {
6195     SMESHDS_GroupBase* oldGroupDS =   orderedOldNewGroups[i]->get<0>();
6196     SMESHDS_Group*   newGroups[2] = { orderedOldNewGroups[i]->get<1>(),
6197                                       orderedOldNewGroups[i]->get<2>() };
6198     const int nbNewGroups = !newGroups[0]->IsEmpty() + !newGroups[1]->IsEmpty();
6199     for ( int is2nd = 0; is2nd < 2; ++is2nd )
6200     {
6201       SMESHDS_Group* newGroupDS = newGroups[ is2nd ];
6202       if ( newGroupDS->IsEmpty() )
6203       {
6204         mesh->GetMeshDS()->RemoveGroup( newGroupDS );
6205       }
6206       else
6207       {
6208         // set group type
6209         newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
6210
6211         // make a name
6212         const bool isTop = ( nbNewGroups == 2 &&
6213                              newGroupDS->GetType() == oldGroupDS->GetType() &&
6214                              is2nd );
6215
6216         string name = oldGroupDS->GetStoreName();
6217         if ( !targetMesh ) {
6218           string suffix = ( isTop ? "top": postfix.c_str() );
6219           name += "_";
6220           name += suffix;
6221           int nb = 1;
6222           while ( !groupNames.insert( name ).second ) // name exists
6223             name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << suffix << "_" << nb++;
6224         }
6225         else if ( isTop ) {
6226           name += "_top";
6227         }
6228         newGroupDS->SetStoreName( name.c_str() );
6229
6230         // make a SMESH_Groups
6231         mesh->AddGroup( newGroupDS );
6232         if ( isTop )
6233           topGrouIds.push_back( newGroupDS->GetID() );
6234         else
6235           newGroupIDs->push_back( newGroupDS->GetID() );
6236       }
6237     }
6238   }
6239   newGroupIDs->splice( newGroupIDs->end(), topGrouIds );
6240
6241   return newGroupIDs;
6242 }
6243
6244 //================================================================================
6245 /*!
6246  * \brief Return list of group of nodes close to each other within theTolerance
6247  *        Search among theNodes or in the whole mesh if theNodes is empty using
6248  *        an Octree algorithm
6249  */
6250 //================================================================================
6251
6252 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6253                                             const double         theTolerance,
6254                                             TListOfListOfNodes & theGroupsOfNodes)
6255 {
6256   myLastCreatedElems.Clear();
6257   myLastCreatedNodes.Clear();
6258
6259   if ( theNodes.empty() )
6260   { // get all nodes in the mesh
6261     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6262     while ( nIt->more() )
6263       theNodes.insert( theNodes.end(),nIt->next());
6264   }
6265
6266   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6267 }
6268
6269 //=======================================================================
6270 //function : SimplifyFace
6271 //purpose  :
6272 //=======================================================================
6273
6274 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *>& faceNodes,
6275                                     vector<const SMDS_MeshNode *>&       poly_nodes,
6276                                     vector<int>&                         quantities) const
6277 {
6278   int nbNodes = faceNodes.size();
6279
6280   if (nbNodes < 3)
6281     return 0;
6282
6283   set<const SMDS_MeshNode*> nodeSet;
6284
6285   // get simple seq of nodes
6286   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6287   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6288   int iSimple = 0, nbUnique = 0;
6289
6290   simpleNodes[iSimple++] = faceNodes[0];
6291   nbUnique++;
6292   for (int iCur = 1; iCur < nbNodes; iCur++) {
6293     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6294       simpleNodes[iSimple++] = faceNodes[iCur];
6295       if (nodeSet.insert( faceNodes[iCur] ).second)
6296         nbUnique++;
6297     }
6298   }
6299   int nbSimple = iSimple;
6300   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6301     nbSimple--;
6302     iSimple--;
6303   }
6304
6305   if (nbUnique < 3)
6306     return 0;
6307
6308   // separate loops
6309   int nbNew = 0;
6310   bool foundLoop = (nbSimple > nbUnique);
6311   while (foundLoop) {
6312     foundLoop = false;
6313     set<const SMDS_MeshNode*> loopSet;
6314     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6315       const SMDS_MeshNode* n = simpleNodes[iSimple];
6316       if (!loopSet.insert( n ).second) {
6317         foundLoop = true;
6318
6319         // separate loop
6320         int iC = 0, curLast = iSimple;
6321         for (; iC < curLast; iC++) {
6322           if (simpleNodes[iC] == n) break;
6323         }
6324         int loopLen = curLast - iC;
6325         if (loopLen > 2) {
6326           // create sub-element
6327           nbNew++;
6328           quantities.push_back(loopLen);
6329           for (; iC < curLast; iC++) {
6330             poly_nodes.push_back(simpleNodes[iC]);
6331           }
6332         }
6333         // shift the rest nodes (place from the first loop position)
6334         for (iC = curLast + 1; iC < nbSimple; iC++) {
6335           simpleNodes[iC - loopLen] = simpleNodes[iC];
6336         }
6337         nbSimple -= loopLen;
6338         iSimple -= loopLen;
6339       }
6340     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6341   } // while (foundLoop)
6342
6343   if (iSimple > 2) {
6344     nbNew++;
6345     quantities.push_back(iSimple);
6346     for (int i = 0; i < iSimple; i++)
6347       poly_nodes.push_back(simpleNodes[i]);
6348   }
6349
6350   return nbNew;
6351 }
6352
6353 //=======================================================================
6354 //function : MergeNodes
6355 //purpose  : In each group, the cdr of nodes are substituted by the first one
6356 //           in all elements.
6357 //=======================================================================
6358
6359 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6360 {
6361   MESSAGE("MergeNodes");
6362   myLastCreatedElems.Clear();
6363   myLastCreatedNodes.Clear();
6364
6365   SMESHDS_Mesh* aMesh = GetMeshDS();
6366
6367   TNodeNodeMap nodeNodeMap; // node to replace - new node
6368   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6369   list< int > rmElemIds, rmNodeIds;
6370
6371   // Fill nodeNodeMap and elems
6372
6373   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6374   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6375     list<const SMDS_MeshNode*>& nodes = *grIt;
6376     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6377     const SMDS_MeshNode* nToKeep = *nIt;
6378     //MESSAGE("node to keep " << nToKeep->GetID());
6379     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6380       const SMDS_MeshNode* nToRemove = *nIt;
6381       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6382       if ( nToRemove != nToKeep ) {
6383         //MESSAGE("  node to remove " << nToRemove->GetID());
6384         rmNodeIds.push_back( nToRemove->GetID() );
6385         AddToSameGroups( nToKeep, nToRemove, aMesh );
6386         // set _alwaysComputed to a sub-mesh of VERTEX to enable mesh computing
6387         // after MergeNodes() w/o creating node in place of merged ones.
6388         const SMDS_PositionPtr& pos = nToRemove->GetPosition();
6389         if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX )
6390           if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() ))
6391             sm->SetIsAlwaysComputed( true );
6392       }
6393
6394       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6395       while ( invElemIt->more() ) {
6396         const SMDS_MeshElement* elem = invElemIt->next();
6397         elems.insert(elem);
6398       }
6399     }
6400   }
6401   // Change element nodes or remove an element
6402
6403   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6404   for ( ; eIt != elems.end(); eIt++ ) {
6405     const SMDS_MeshElement* elem = *eIt;
6406     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
6407     int nbNodes = elem->NbNodes();
6408     int aShapeId = FindShape( elem );
6409
6410     set<const SMDS_MeshNode*> nodeSet;
6411     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6412     int iUnique = 0, iCur = 0, nbRepl = 0;
6413     vector<int> iRepl( nbNodes );
6414
6415     // get new seq of nodes
6416     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6417     while ( itN->more() ) {
6418       const SMDS_MeshNode* n =
6419         static_cast<const SMDS_MeshNode*>( itN->next() );
6420
6421       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6422       if ( nnIt != nodeNodeMap.end() ) { // n sticks
6423         n = (*nnIt).second;
6424         // BUG 0020185: begin
6425         {
6426           bool stopRecur = false;
6427           set<const SMDS_MeshNode*> nodesRecur;
6428           nodesRecur.insert(n);
6429           while (!stopRecur) {
6430             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6431             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6432               n = (*nnIt_i).second;
6433               if (!nodesRecur.insert(n).second) {
6434                 // error: recursive dependancy
6435                 stopRecur = true;
6436               }
6437             }
6438             else
6439               stopRecur = true;
6440           }
6441         }
6442         // BUG 0020185: end
6443       }
6444       curNodes[ iCur ] = n;
6445       bool isUnique = nodeSet.insert( n ).second;
6446       if ( isUnique )
6447         uniqueNodes[ iUnique++ ] = n;
6448       else
6449         iRepl[ nbRepl++ ] = iCur;
6450       iCur++;
6451     }
6452
6453     // Analyse element topology after replacement
6454
6455     bool isOk = true;
6456     int nbUniqueNodes = nodeSet.size();
6457     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
6458     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6459       // Polygons and Polyhedral volumes
6460       if (elem->IsPoly()) {
6461
6462         if (elem->GetType() == SMDSAbs_Face) {
6463           // Polygon
6464           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6465           int inode = 0;
6466           for (; inode < nbNodes; inode++) {
6467             face_nodes[inode] = curNodes[inode];
6468           }
6469
6470           vector<const SMDS_MeshNode *> polygons_nodes;
6471           vector<int> quantities;
6472           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6473           if (nbNew > 0) {
6474             inode = 0;
6475             for (int iface = 0; iface < nbNew; iface++) {
6476               int nbNodes = quantities[iface];
6477               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6478               for (int ii = 0; ii < nbNodes; ii++, inode++) {
6479                 poly_nodes[ii] = polygons_nodes[inode];
6480               }
6481               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6482               myLastCreatedElems.Append(newElem);
6483               if (aShapeId)
6484                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6485             }
6486
6487             MESSAGE("ChangeElementNodes MergeNodes Polygon");
6488             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6489             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
6490             int quid =0;
6491             if (nbNew > 0) quid = nbNew - 1;
6492             vector<int> newquant(quantities.begin()+quid, quantities.end());
6493             const SMDS_MeshElement* newElem = 0;
6494             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
6495             myLastCreatedElems.Append(newElem);
6496             if ( aShapeId && newElem )
6497               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6498             rmElemIds.push_back(elem->GetID());
6499           }
6500           else {
6501             rmElemIds.push_back(elem->GetID());
6502           }
6503
6504         }
6505         else if (elem->GetType() == SMDSAbs_Volume) {
6506           // Polyhedral volume
6507           if (nbUniqueNodes < 4) {
6508             rmElemIds.push_back(elem->GetID());
6509           }
6510           else {
6511             // each face has to be analyzed in order to check volume validity
6512             const SMDS_VtkVolume* aPolyedre =
6513               dynamic_cast<const SMDS_VtkVolume*>( elem );
6514             if (aPolyedre) {
6515               int nbFaces = aPolyedre->NbFaces();
6516
6517               vector<const SMDS_MeshNode *> poly_nodes;
6518               vector<int> quantities;
6519
6520               for (int iface = 1; iface <= nbFaces; iface++) {
6521                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6522                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
6523
6524                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
6525                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
6526                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
6527                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
6528                     faceNode = (*nnIt).second;
6529                   }
6530                   faceNodes[inode - 1] = faceNode;
6531                 }
6532
6533                 SimplifyFace(faceNodes, poly_nodes, quantities);
6534               }
6535
6536               if (quantities.size() > 3) {
6537                 // to be done: remove coincident faces
6538               }
6539
6540               if (quantities.size() > 3)
6541                 {
6542                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
6543                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6544                   const SMDS_MeshElement* newElem = 0;
6545                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
6546                   myLastCreatedElems.Append(newElem);
6547                   if ( aShapeId && newElem )
6548                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
6549                   rmElemIds.push_back(elem->GetID());
6550                 }
6551             }
6552             else {
6553               rmElemIds.push_back(elem->GetID());
6554             }
6555           }
6556         }
6557         else {
6558         }
6559
6560         continue;
6561       } // poly element
6562
6563       // Regular elements
6564       // TODO not all the possible cases are solved. Find something more generic?
6565       switch ( nbNodes ) {
6566       case 2: ///////////////////////////////////// EDGE
6567         isOk = false; break;
6568       case 3: ///////////////////////////////////// TRIANGLE
6569         isOk = false; break;
6570       case 4:
6571         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
6572           isOk = false;
6573         else { //////////////////////////////////// QUADRANGLE
6574           if ( nbUniqueNodes < 3 )
6575             isOk = false;
6576           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
6577             isOk = false; // opposite nodes stick
6578           //MESSAGE("isOk " << isOk);
6579         }
6580         break;
6581       case 6: ///////////////////////////////////// PENTAHEDRON
6582         if ( nbUniqueNodes == 4 ) {
6583           // ---------------------------------> tetrahedron
6584           if (nbRepl == 3 &&
6585               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
6586             // all top nodes stick: reverse a bottom
6587             uniqueNodes[ 0 ] = curNodes [ 1 ];
6588             uniqueNodes[ 1 ] = curNodes [ 0 ];
6589           }
6590           else if (nbRepl == 3 &&
6591                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
6592             // all bottom nodes stick: set a top before
6593             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
6594             uniqueNodes[ 0 ] = curNodes [ 3 ];
6595             uniqueNodes[ 1 ] = curNodes [ 4 ];
6596             uniqueNodes[ 2 ] = curNodes [ 5 ];
6597           }
6598           else if (nbRepl == 4 &&
6599                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
6600             // a lateral face turns into a line: reverse a bottom
6601             uniqueNodes[ 0 ] = curNodes [ 1 ];
6602             uniqueNodes[ 1 ] = curNodes [ 0 ];
6603           }
6604           else
6605             isOk = false;
6606         }
6607         else if ( nbUniqueNodes == 5 ) {
6608           // PENTAHEDRON --------------------> 2 tetrahedrons
6609           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6610             // a bottom node sticks with a linked top one
6611             // 1.
6612             SMDS_MeshElement* newElem =
6613               aMesh->AddVolume(curNodes[ 3 ],
6614                                curNodes[ 4 ],
6615                                curNodes[ 5 ],
6616                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6617             myLastCreatedElems.Append(newElem);
6618             if ( aShapeId )
6619               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6620             // 2. : reverse a bottom
6621             uniqueNodes[ 0 ] = curNodes [ 1 ];
6622             uniqueNodes[ 1 ] = curNodes [ 0 ];
6623             nbUniqueNodes = 4;
6624           }
6625           else
6626             isOk = false;
6627         }
6628         else
6629           isOk = false;
6630         break;
6631       case 8: {
6632         if(elem->IsQuadratic()) { // Quadratic quadrangle
6633           //   1    5    2
6634           //    +---+---+
6635           //    |       |
6636           //    |       |
6637           //   4+       +6
6638           //    |       |
6639           //    |       |
6640           //    +---+---+
6641           //   0    7    3
6642           isOk = false;
6643           if(nbRepl==2) {
6644             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
6645           }
6646           if(nbRepl==3) {
6647             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
6648             nbUniqueNodes = 6;
6649             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6650               uniqueNodes[0] = curNodes[0];
6651               uniqueNodes[1] = curNodes[2];
6652               uniqueNodes[2] = curNodes[3];
6653               uniqueNodes[3] = curNodes[5];
6654               uniqueNodes[4] = curNodes[6];
6655               uniqueNodes[5] = curNodes[7];
6656               isOk = true;
6657             }
6658             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6659               uniqueNodes[0] = curNodes[0];
6660               uniqueNodes[1] = curNodes[1];
6661               uniqueNodes[2] = curNodes[2];
6662               uniqueNodes[3] = curNodes[4];
6663               uniqueNodes[4] = curNodes[5];
6664               uniqueNodes[5] = curNodes[6];
6665               isOk = true;
6666             }
6667             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6668               uniqueNodes[0] = curNodes[1];
6669               uniqueNodes[1] = curNodes[2];
6670               uniqueNodes[2] = curNodes[3];
6671               uniqueNodes[3] = curNodes[5];
6672               uniqueNodes[4] = curNodes[6];
6673               uniqueNodes[5] = curNodes[0];
6674               isOk = true;
6675             }
6676             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
6677               uniqueNodes[0] = curNodes[0];
6678               uniqueNodes[1] = curNodes[1];
6679               uniqueNodes[2] = curNodes[3];
6680               uniqueNodes[3] = curNodes[4];
6681               uniqueNodes[4] = curNodes[6];
6682               uniqueNodes[5] = curNodes[7];
6683               isOk = true;
6684             }
6685             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
6686               uniqueNodes[0] = curNodes[0];
6687               uniqueNodes[1] = curNodes[2];
6688               uniqueNodes[2] = curNodes[3];
6689               uniqueNodes[3] = curNodes[1];
6690               uniqueNodes[4] = curNodes[6];
6691               uniqueNodes[5] = curNodes[7];
6692               isOk = true;
6693             }
6694             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
6695               uniqueNodes[0] = curNodes[0];
6696               uniqueNodes[1] = curNodes[1];
6697               uniqueNodes[2] = curNodes[2];
6698               uniqueNodes[3] = curNodes[4];
6699               uniqueNodes[4] = curNodes[5];
6700               uniqueNodes[5] = curNodes[7];
6701               isOk = true;
6702             }
6703             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
6704               uniqueNodes[0] = curNodes[0];
6705               uniqueNodes[1] = curNodes[1];
6706               uniqueNodes[2] = curNodes[3];
6707               uniqueNodes[3] = curNodes[4];
6708               uniqueNodes[4] = curNodes[2];
6709               uniqueNodes[5] = curNodes[7];
6710               isOk = true;
6711             }
6712             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
6713               uniqueNodes[0] = curNodes[0];
6714               uniqueNodes[1] = curNodes[1];
6715               uniqueNodes[2] = curNodes[2];
6716               uniqueNodes[3] = curNodes[4];
6717               uniqueNodes[4] = curNodes[5];
6718               uniqueNodes[5] = curNodes[3];
6719               isOk = true;
6720             }
6721           }
6722           if(nbRepl==4) {
6723             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
6724           }
6725           if(nbRepl==5) {
6726             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
6727           }
6728           break;
6729         }
6730         //////////////////////////////////// HEXAHEDRON
6731         isOk = false;
6732         SMDS_VolumeTool hexa (elem);
6733         hexa.SetExternalNormal();
6734         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
6735           //////////////////////// HEX ---> 1 tetrahedron
6736           for ( int iFace = 0; iFace < 6; iFace++ ) {
6737             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6738             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6739                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6740                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6741               // one face turns into a point ...
6742               int iOppFace = hexa.GetOppFaceIndex( iFace );
6743               ind = hexa.GetFaceNodesIndices( iOppFace );
6744               int nbStick = 0;
6745               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
6746                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6747                   nbStick++;
6748               }
6749               if ( nbStick == 1 ) {
6750                 // ... and the opposite one - into a triangle.
6751                 // set a top node
6752                 ind = hexa.GetFaceNodesIndices( iFace );
6753                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
6754                 isOk = true;
6755               }
6756               break;
6757             }
6758           }
6759         }
6760         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
6761           //////////////////////// HEX ---> 1 prism
6762           int nbTria = 0, iTria[3];
6763           const int *ind; // indices of face nodes
6764           // look for triangular faces
6765           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
6766             ind = hexa.GetFaceNodesIndices( iFace );
6767             TIDSortedNodeSet faceNodes;
6768             for ( iCur = 0; iCur < 4; iCur++ )
6769               faceNodes.insert( curNodes[ind[iCur]] );
6770             if ( faceNodes.size() == 3 )
6771               iTria[ nbTria++ ] = iFace;
6772           }
6773           // check if triangles are opposite
6774           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
6775           {
6776             isOk = true;
6777             // set nodes of the bottom triangle
6778             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
6779             vector<int> indB;
6780             for ( iCur = 0; iCur < 4; iCur++ )
6781               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
6782                 indB.push_back( ind[iCur] );
6783             if ( !hexa.IsForward() )
6784               std::swap( indB[0], indB[2] );
6785             for ( iCur = 0; iCur < 3; iCur++ )
6786               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
6787             // set nodes of the top triangle
6788             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
6789             for ( iCur = 0; iCur < 3; ++iCur )
6790               for ( int j = 0; j < 4; ++j )
6791                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
6792                 {
6793                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
6794                   break;
6795                 }
6796           }
6797           break;
6798         }
6799         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
6800           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
6801           for ( int iFace = 0; iFace < 6; iFace++ ) {
6802             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6803             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6804                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6805                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6806               // one face turns into a point ...
6807               int iOppFace = hexa.GetOppFaceIndex( iFace );
6808               ind = hexa.GetFaceNodesIndices( iOppFace );
6809               int nbStick = 0;
6810               iUnique = 2;  // reverse a tetrahedron 1 bottom
6811               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
6812                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6813                   nbStick++;
6814                 else if ( iUnique >= 0 )
6815                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6816               }
6817               if ( nbStick == 0 ) {
6818                 // ... and the opposite one is a quadrangle
6819                 // set a top node
6820                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
6821                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
6822                 nbUniqueNodes = 4;
6823                 // tetrahedron 2
6824                 SMDS_MeshElement* newElem =
6825                   aMesh->AddVolume(curNodes[ind[ 0 ]],
6826                                    curNodes[ind[ 3 ]],
6827                                    curNodes[ind[ 2 ]],
6828                                    curNodes[indTop[ 0 ]]);
6829                 myLastCreatedElems.Append(newElem);
6830                 if ( aShapeId )
6831                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
6832                 isOk = true;
6833               }
6834               break;
6835             }
6836           }
6837         }
6838         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
6839           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
6840           // find indices of quad and tri faces
6841           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
6842           for ( iFace = 0; iFace < 6; iFace++ ) {
6843             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6844             nodeSet.clear();
6845             for ( iCur = 0; iCur < 4; iCur++ )
6846               nodeSet.insert( curNodes[ind[ iCur ]] );
6847             nbUniqueNodes = nodeSet.size();
6848             if ( nbUniqueNodes == 3 )
6849               iTriFace[ nbTri++ ] = iFace;
6850             else if ( nbUniqueNodes == 4 )
6851               iQuadFace[ nbQuad++ ] = iFace;
6852           }
6853           if (nbQuad == 2 && nbTri == 4 &&
6854               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
6855             // 2 opposite quadrangles stuck with a diagonal;
6856             // sample groups of merged indices: (0-4)(2-6)
6857             // --------------------------------------------> 2 tetrahedrons
6858             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
6859             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
6860             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
6861             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
6862                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
6863               // stuck with 0-2 diagonal
6864               i0  = ind1[ 3 ];
6865               i1d = ind1[ 0 ];
6866               i2  = ind1[ 1 ];
6867               i3d = ind1[ 2 ];
6868               i0t = ind2[ 1 ];
6869               i2t = ind2[ 3 ];
6870             }
6871             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
6872                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
6873               // stuck with 1-3 diagonal
6874               i0  = ind1[ 0 ];
6875               i1d = ind1[ 1 ];
6876               i2  = ind1[ 2 ];
6877               i3d = ind1[ 3 ];
6878               i0t = ind2[ 0 ];
6879               i2t = ind2[ 1 ];
6880             }
6881             else {
6882               ASSERT(0);
6883             }
6884             // tetrahedron 1
6885             uniqueNodes[ 0 ] = curNodes [ i0 ];
6886             uniqueNodes[ 1 ] = curNodes [ i1d ];
6887             uniqueNodes[ 2 ] = curNodes [ i3d ];
6888             uniqueNodes[ 3 ] = curNodes [ i0t ];
6889             nbUniqueNodes = 4;
6890             // tetrahedron 2
6891             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
6892                                                          curNodes[ i2 ],
6893                                                          curNodes[ i3d ],
6894                                                          curNodes[ i2t ]);
6895             myLastCreatedElems.Append(newElem);
6896             if ( aShapeId )
6897               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6898             isOk = true;
6899           }
6900           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
6901                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
6902             // --------------------------------------------> prism
6903             // find 2 opposite triangles
6904             nbUniqueNodes = 6;
6905             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
6906               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
6907                 // find indices of kept and replaced nodes
6908                 // and fill unique nodes of 2 opposite triangles
6909                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
6910                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
6911                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
6912                 // fill unique nodes
6913                 iUnique = 0;
6914                 isOk = true;
6915                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
6916                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
6917                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
6918                   if ( n == nInit ) {
6919                     // iCur of a linked node of the opposite face (make normals co-directed):
6920                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
6921                     // check that correspondent corners of triangles are linked
6922                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
6923                       isOk = false;
6924                     else {
6925                       uniqueNodes[ iUnique ] = n;
6926                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
6927                       iUnique++;
6928                     }
6929                   }
6930                 }
6931                 break;
6932               }
6933             }
6934           }
6935         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
6936         else
6937         {
6938           MESSAGE("MergeNodes() removes hexahedron "<< elem);
6939         }
6940         break;
6941       } // HEXAHEDRON
6942
6943       default:
6944         isOk = false;
6945       } // switch ( nbNodes )
6946
6947     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
6948
6949     if ( isOk ) { // the elem remains valid after sticking nodes
6950       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
6951       {
6952         // Change nodes of polyedre
6953         const SMDS_VtkVolume* aPolyedre =
6954           dynamic_cast<const SMDS_VtkVolume*>( elem );
6955         if (aPolyedre) {
6956           int nbFaces = aPolyedre->NbFaces();
6957
6958           vector<const SMDS_MeshNode *> poly_nodes;
6959           vector<int> quantities (nbFaces);
6960
6961           for (int iface = 1; iface <= nbFaces; iface++) {
6962             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6963             quantities[iface - 1] = nbFaceNodes;
6964
6965             for (inode = 1; inode <= nbFaceNodes; inode++) {
6966               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
6967
6968               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
6969               if (nnIt != nodeNodeMap.end()) { // curNode sticks
6970                 curNode = (*nnIt).second;
6971               }
6972               poly_nodes.push_back(curNode);
6973             }
6974           }
6975           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
6976         }
6977       }
6978       else // replace non-polyhedron elements
6979       {
6980         const SMDSAbs_ElementType etyp = elem->GetType();
6981         const int elemId               = elem->GetID();
6982         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
6983         uniqueNodes.resize(nbUniqueNodes);
6984
6985         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
6986
6987         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
6988         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
6989         if ( sm && newElem )
6990           sm->AddElement( newElem );
6991         if ( elem != newElem )
6992           ReplaceElemInGroups( elem, newElem, aMesh );
6993       }
6994     }
6995     else {
6996       // Remove invalid regular element or invalid polygon
6997       rmElemIds.push_back( elem->GetID() );
6998     }
6999
7000   } // loop on elements
7001
7002   // Remove bad elements, then equal nodes (order important)
7003
7004   Remove( rmElemIds, false );
7005   Remove( rmNodeIds, true );
7006
7007 }
7008
7009
7010 // ========================================================
7011 // class   : SortableElement
7012 // purpose : allow sorting elements basing on their nodes
7013 // ========================================================
7014 class SortableElement : public set <const SMDS_MeshElement*>
7015 {
7016 public:
7017
7018   SortableElement( const SMDS_MeshElement* theElem )
7019   {
7020     myElem = theElem;
7021     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7022     while ( nodeIt->more() )
7023       this->insert( nodeIt->next() );
7024   }
7025
7026   const SMDS_MeshElement* Get() const
7027   { return myElem; }
7028
7029   void Set(const SMDS_MeshElement* e) const
7030   { myElem = e; }
7031
7032
7033 private:
7034   mutable const SMDS_MeshElement* myElem;
7035 };
7036
7037 //=======================================================================
7038 //function : FindEqualElements
7039 //purpose  : Return list of group of elements built on the same nodes.
7040 //           Search among theElements or in the whole mesh if theElements is empty
7041 //=======================================================================
7042
7043 void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet &        theElements,
7044                                          TListOfListOfElementsID & theGroupsOfElementsID)
7045 {
7046   myLastCreatedElems.Clear();
7047   myLastCreatedNodes.Clear();
7048
7049   typedef map< SortableElement, int > TMapOfNodeSet;
7050   typedef list<int> TGroupOfElems;
7051
7052   if ( theElements.empty() )
7053   { // get all elements in the mesh
7054     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7055     while ( eIt->more() )
7056       theElements.insert( theElements.end(), eIt->next());
7057   }
7058
7059   vector< TGroupOfElems > arrayOfGroups;
7060   TGroupOfElems groupOfElems;
7061   TMapOfNodeSet mapOfNodeSet;
7062
7063   TIDSortedElemSet::iterator elemIt = theElements.begin();
7064   for ( int i = 0, j=0; elemIt != theElements.end(); ++elemIt, ++j ) {
7065     const SMDS_MeshElement* curElem = *elemIt;
7066     SortableElement SE(curElem);
7067     int ind = -1;
7068     // check uniqueness
7069     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7070     if( !(pp.second) ) {
7071       TMapOfNodeSet::iterator& itSE = pp.first;
7072       ind = (*itSE).second;
7073       arrayOfGroups[ind].push_back(curElem->GetID());
7074     }
7075     else {
7076       groupOfElems.clear();
7077       groupOfElems.push_back(curElem->GetID());
7078       arrayOfGroups.push_back(groupOfElems);
7079       i++;
7080     }
7081   }
7082
7083   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7084   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7085     groupOfElems = *groupIt;
7086     if ( groupOfElems.size() > 1 ) {
7087       groupOfElems.sort();
7088       theGroupsOfElementsID.push_back(groupOfElems);
7089     }
7090   }
7091 }
7092
7093 //=======================================================================
7094 //function : MergeElements
7095 //purpose  : In each given group, substitute all elements by the first one.
7096 //=======================================================================
7097
7098 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7099 {
7100   myLastCreatedElems.Clear();
7101   myLastCreatedNodes.Clear();
7102
7103   typedef list<int> TListOfIDs;
7104   TListOfIDs rmElemIds; // IDs of elems to remove
7105
7106   SMESHDS_Mesh* aMesh = GetMeshDS();
7107
7108   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7109   while ( groupsIt != theGroupsOfElementsID.end() ) {
7110     TListOfIDs& aGroupOfElemID = *groupsIt;
7111     aGroupOfElemID.sort();
7112     int elemIDToKeep = aGroupOfElemID.front();
7113     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7114     aGroupOfElemID.pop_front();
7115     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7116     while ( idIt != aGroupOfElemID.end() ) {
7117       int elemIDToRemove = *idIt;
7118       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7119       // add the kept element in groups of removed one (PAL15188)
7120       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7121       rmElemIds.push_back( elemIDToRemove );
7122       ++idIt;
7123     }
7124     ++groupsIt;
7125   }
7126
7127   Remove( rmElemIds, false );
7128 }
7129
7130 //=======================================================================
7131 //function : MergeEqualElements
7132 //purpose  : Remove all but one of elements built on the same nodes.
7133 //=======================================================================
7134
7135 void SMESH_MeshEditor::MergeEqualElements()
7136 {
7137   TIDSortedElemSet aMeshElements; /* empty input ==
7138                                      to merge equal elements in the whole mesh */
7139   TListOfListOfElementsID aGroupsOfElementsID;
7140   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7141   MergeElements(aGroupsOfElementsID);
7142 }
7143
7144 //=======================================================================
7145 //function : findAdjacentFace
7146 //purpose  :
7147 //=======================================================================
7148
7149 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7150                                                 const SMDS_MeshNode* n2,
7151                                                 const SMDS_MeshElement* elem)
7152 {
7153   TIDSortedElemSet elemSet, avoidSet;
7154   if ( elem )
7155     avoidSet.insert ( elem );
7156   return SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet );
7157 }
7158
7159 //=======================================================================
7160 //function : FindFreeBorder
7161 //purpose  :
7162 //=======================================================================
7163
7164 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7165
7166 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7167                                        const SMDS_MeshNode*             theSecondNode,
7168                                        const SMDS_MeshNode*             theLastNode,
7169                                        list< const SMDS_MeshNode* > &   theNodes,
7170                                        list< const SMDS_MeshElement* >& theFaces)
7171 {
7172   if ( !theFirstNode || !theSecondNode )
7173     return false;
7174   // find border face between theFirstNode and theSecondNode
7175   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7176   if ( !curElem )
7177     return false;
7178
7179   theFaces.push_back( curElem );
7180   theNodes.push_back( theFirstNode );
7181   theNodes.push_back( theSecondNode );
7182
7183   //vector<const SMDS_MeshNode*> nodes;
7184   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7185   TIDSortedElemSet foundElems;
7186   bool needTheLast = ( theLastNode != 0 );
7187
7188   while ( nStart != theLastNode ) {
7189     if ( nStart == theFirstNode )
7190       return !needTheLast;
7191
7192     // find all free border faces sharing form nStart
7193
7194     list< const SMDS_MeshElement* > curElemList;
7195     list< const SMDS_MeshNode* > nStartList;
7196     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7197     while ( invElemIt->more() ) {
7198       const SMDS_MeshElement* e = invElemIt->next();
7199       if ( e == curElem || foundElems.insert( e ).second ) {
7200         // get nodes
7201         int iNode = 0, nbNodes = e->NbNodes();
7202         //const SMDS_MeshNode* nodes[nbNodes+1];
7203         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7204
7205         if(e->IsQuadratic()) {
7206           const SMDS_VtkFace* F =
7207             dynamic_cast<const SMDS_VtkFace*>(e);
7208           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7209           // use special nodes iterator
7210           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7211           while( anIter->more() ) {
7212             nodes[ iNode++ ] = cast2Node(anIter->next());
7213           }
7214         }
7215         else {
7216           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7217           while ( nIt->more() )
7218             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7219         }
7220         nodes[ iNode ] = nodes[ 0 ];
7221         // check 2 links
7222         for ( iNode = 0; iNode < nbNodes; iNode++ )
7223           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7224                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7225               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7226           {
7227             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7228             curElemList.push_back( e );
7229           }
7230       }
7231     }
7232     // analyse the found
7233
7234     int nbNewBorders = curElemList.size();
7235     if ( nbNewBorders == 0 ) {
7236       // no free border furthermore
7237       return !needTheLast;
7238     }
7239     else if ( nbNewBorders == 1 ) {
7240       // one more element found
7241       nIgnore = nStart;
7242       nStart = nStartList.front();
7243       curElem = curElemList.front();
7244       theFaces.push_back( curElem );
7245       theNodes.push_back( nStart );
7246     }
7247     else {
7248       // several continuations found
7249       list< const SMDS_MeshElement* >::iterator curElemIt;
7250       list< const SMDS_MeshNode* >::iterator nStartIt;
7251       // check if one of them reached the last node
7252       if ( needTheLast ) {
7253         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7254              curElemIt!= curElemList.end();
7255              curElemIt++, nStartIt++ )
7256           if ( *nStartIt == theLastNode ) {
7257             theFaces.push_back( *curElemIt );
7258             theNodes.push_back( *nStartIt );
7259             return true;
7260           }
7261       }
7262       // find the best free border by the continuations
7263       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7264       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7265       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7266            curElemIt!= curElemList.end();
7267            curElemIt++, nStartIt++ )
7268       {
7269         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7270         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7271         // find one more free border
7272         if ( ! SMESH_MeshEditor::FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7273           cNL->clear();
7274           cFL->clear();
7275         }
7276         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7277           // choice: clear a worse one
7278           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7279           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7280           contNodes[ iWorse ].clear();
7281           contFaces[ iWorse ].clear();
7282         }
7283       }
7284       if ( contNodes[0].empty() && contNodes[1].empty() )
7285         return false;
7286
7287       // append the best free border
7288       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7289       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7290       theNodes.pop_back(); // remove nIgnore
7291       theNodes.pop_back(); // remove nStart
7292       theFaces.pop_back(); // remove curElem
7293       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7294       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7295       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7296       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7297       return true;
7298
7299     } // several continuations found
7300   } // while ( nStart != theLastNode )
7301
7302   return true;
7303 }
7304
7305 //=======================================================================
7306 //function : CheckFreeBorderNodes
7307 //purpose  : Return true if the tree nodes are on a free border
7308 //=======================================================================
7309
7310 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7311                                             const SMDS_MeshNode* theNode2,
7312                                             const SMDS_MeshNode* theNode3)
7313 {
7314   list< const SMDS_MeshNode* > nodes;
7315   list< const SMDS_MeshElement* > faces;
7316   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7317 }
7318
7319 //=======================================================================
7320 //function : SewFreeBorder
7321 //purpose  :
7322 //=======================================================================
7323
7324 SMESH_MeshEditor::Sew_Error
7325 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7326                                  const SMDS_MeshNode* theBordSecondNode,
7327                                  const SMDS_MeshNode* theBordLastNode,
7328                                  const SMDS_MeshNode* theSideFirstNode,
7329                                  const SMDS_MeshNode* theSideSecondNode,
7330                                  const SMDS_MeshNode* theSideThirdNode,
7331                                  const bool           theSideIsFreeBorder,
7332                                  const bool           toCreatePolygons,
7333                                  const bool           toCreatePolyedrs)
7334 {
7335   myLastCreatedElems.Clear();
7336   myLastCreatedNodes.Clear();
7337
7338   MESSAGE("::SewFreeBorder()");
7339   Sew_Error aResult = SEW_OK;
7340
7341   // ====================================
7342   //    find side nodes and elements
7343   // ====================================
7344
7345   list< const SMDS_MeshNode* > nSide[ 2 ];
7346   list< const SMDS_MeshElement* > eSide[ 2 ];
7347   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7348   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7349
7350   // Free border 1
7351   // --------------
7352   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7353                       nSide[0], eSide[0])) {
7354     MESSAGE(" Free Border 1 not found " );
7355     aResult = SEW_BORDER1_NOT_FOUND;
7356   }
7357   if (theSideIsFreeBorder) {
7358     // Free border 2
7359     // --------------
7360     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7361                         nSide[1], eSide[1])) {
7362       MESSAGE(" Free Border 2 not found " );
7363       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7364     }
7365   }
7366   if ( aResult != SEW_OK )
7367     return aResult;
7368
7369   if (!theSideIsFreeBorder) {
7370     // Side 2
7371     // --------------
7372
7373     // -------------------------------------------------------------------------
7374     // Algo:
7375     // 1. If nodes to merge are not coincident, move nodes of the free border
7376     //    from the coord sys defined by the direction from the first to last
7377     //    nodes of the border to the correspondent sys of the side 2
7378     // 2. On the side 2, find the links most co-directed with the correspondent
7379     //    links of the free border
7380     // -------------------------------------------------------------------------
7381
7382     // 1. Since sewing may break if there are volumes to split on the side 2,
7383     //    we wont move nodes but just compute new coordinates for them
7384     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7385     TNodeXYZMap nBordXYZ;
7386     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7387     list< const SMDS_MeshNode* >::iterator nBordIt;
7388
7389     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7390     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7391     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7392     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7393     double tol2 = 1.e-8;
7394     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7395     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7396       // Need node movement.
7397
7398       // find X and Z axes to create trsf
7399       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7400       gp_Vec X = Zs ^ Zb;
7401       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7402         // Zb || Zs
7403         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7404
7405       // coord systems
7406       gp_Ax3 toBordAx( Pb1, Zb, X );
7407       gp_Ax3 fromSideAx( Ps1, Zs, X );
7408       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7409       // set trsf
7410       gp_Trsf toBordSys, fromSide2Sys;
7411       toBordSys.SetTransformation( toBordAx );
7412       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7413       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7414
7415       // move
7416       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7417         const SMDS_MeshNode* n = *nBordIt;
7418         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7419         toBordSys.Transforms( xyz );
7420         fromSide2Sys.Transforms( xyz );
7421         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7422       }
7423     }
7424     else {
7425       // just insert nodes XYZ in the nBordXYZ map
7426       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7427         const SMDS_MeshNode* n = *nBordIt;
7428         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7429       }
7430     }
7431
7432     // 2. On the side 2, find the links most co-directed with the correspondent
7433     //    links of the free border
7434
7435     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7436     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7437     sideNodes.push_back( theSideFirstNode );
7438
7439     bool hasVolumes = false;
7440     LinkID_Gen aLinkID_Gen( GetMeshDS() );
7441     set<long> foundSideLinkIDs, checkedLinkIDs;
7442     SMDS_VolumeTool volume;
7443     //const SMDS_MeshNode* faceNodes[ 4 ];
7444
7445     const SMDS_MeshNode*    sideNode;
7446     const SMDS_MeshElement* sideElem;
7447     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7448     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7449     nBordIt = bordNodes.begin();
7450     nBordIt++;
7451     // border node position and border link direction to compare with
7452     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7453     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7454     // choose next side node by link direction or by closeness to
7455     // the current border node:
7456     bool searchByDir = ( *nBordIt != theBordLastNode );
7457     do {
7458       // find the next node on the Side 2
7459       sideNode = 0;
7460       double maxDot = -DBL_MAX, minDist = DBL_MAX;
7461       long linkID;
7462       checkedLinkIDs.clear();
7463       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7464
7465       // loop on inverse elements of current node (prevSideNode) on the Side 2
7466       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7467       while ( invElemIt->more() )
7468       {
7469         const SMDS_MeshElement* elem = invElemIt->next();
7470         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7471         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7472         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7473         bool isVolume = volume.Set( elem );
7474         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7475         if ( isVolume ) // --volume
7476           hasVolumes = true;
7477         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7478           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7479           if(elem->IsQuadratic()) {
7480             const SMDS_VtkFace* F =
7481               dynamic_cast<const SMDS_VtkFace*>(elem);
7482             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7483             // use special nodes iterator
7484             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7485             while( anIter->more() ) {
7486               nodes[ iNode ] = cast2Node(anIter->next());
7487               if ( nodes[ iNode++ ] == prevSideNode )
7488                 iPrevNode = iNode - 1;
7489             }
7490           }
7491           else {
7492             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7493             while ( nIt->more() ) {
7494               nodes[ iNode ] = cast2Node( nIt->next() );
7495               if ( nodes[ iNode++ ] == prevSideNode )
7496                 iPrevNode = iNode - 1;
7497             }
7498           }
7499           // there are 2 links to check
7500           nbNodes = 2;
7501         }
7502         else // --edge
7503           continue;
7504         // loop on links, to be precise, on the second node of links
7505         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7506           const SMDS_MeshNode* n = nodes[ iNode ];
7507           if ( isVolume ) {
7508             if ( !volume.IsLinked( n, prevSideNode ))
7509               continue;
7510           }
7511           else {
7512             if ( iNode ) // a node before prevSideNode
7513               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7514             else         // a node after prevSideNode
7515               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7516           }
7517           // check if this link was already used
7518           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7519           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7520           if (!isJustChecked &&
7521               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7522           {
7523             // test a link geometrically
7524             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
7525             bool linkIsBetter = false;
7526             double dot = 0.0, dist = 0.0;
7527             if ( searchByDir ) { // choose most co-directed link
7528               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
7529               linkIsBetter = ( dot > maxDot );
7530             }
7531             else { // choose link with the node closest to bordPos
7532               dist = ( nextXYZ - bordPos ).SquareModulus();
7533               linkIsBetter = ( dist < minDist );
7534             }
7535             if ( linkIsBetter ) {
7536               maxDot = dot;
7537               minDist = dist;
7538               linkID = iLink;
7539               sideNode = n;
7540               sideElem = elem;
7541             }
7542           }
7543         }
7544       } // loop on inverse elements of prevSideNode
7545
7546       if ( !sideNode ) {
7547         MESSAGE(" Cant find path by links of the Side 2 ");
7548         return SEW_BAD_SIDE_NODES;
7549       }
7550       sideNodes.push_back( sideNode );
7551       sideElems.push_back( sideElem );
7552       foundSideLinkIDs.insert ( linkID );
7553       prevSideNode = sideNode;
7554
7555       if ( *nBordIt == theBordLastNode )
7556         searchByDir = false;
7557       else {
7558         // find the next border link to compare with
7559         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
7560         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7561         // move to next border node if sideNode is before forward border node (bordPos)
7562         while ( *nBordIt != theBordLastNode && !searchByDir ) {
7563           prevBordNode = *nBordIt;
7564           nBordIt++;
7565           bordPos = nBordXYZ[ *nBordIt ];
7566           bordDir = bordPos - nBordXYZ[ prevBordNode ];
7567           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7568         }
7569       }
7570     }
7571     while ( sideNode != theSideSecondNode );
7572
7573     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
7574       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
7575       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
7576     }
7577   } // end nodes search on the side 2
7578
7579   // ============================
7580   // sew the border to the side 2
7581   // ============================
7582
7583   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
7584   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
7585
7586   TListOfListOfNodes nodeGroupsToMerge;
7587   if ( nbNodes[0] == nbNodes[1] ||
7588        ( theSideIsFreeBorder && !theSideThirdNode)) {
7589
7590     // all nodes are to be merged
7591
7592     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
7593          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
7594          nIt[0]++, nIt[1]++ )
7595     {
7596       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7597       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
7598       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
7599     }
7600   }
7601   else {
7602
7603     // insert new nodes into the border and the side to get equal nb of segments
7604
7605     // get normalized parameters of nodes on the borders
7606     //double param[ 2 ][ maxNbNodes ];
7607     double* param[ 2 ];
7608     param[0] = new double [ maxNbNodes ];
7609     param[1] = new double [ maxNbNodes ];
7610     int iNode, iBord;
7611     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7612       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7613       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
7614       const SMDS_MeshNode* nPrev = *nIt;
7615       double bordLength = 0;
7616       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7617         const SMDS_MeshNode* nCur = *nIt;
7618         gp_XYZ segment (nCur->X() - nPrev->X(),
7619                         nCur->Y() - nPrev->Y(),
7620                         nCur->Z() - nPrev->Z());
7621         double segmentLen = segment.Modulus();
7622         bordLength += segmentLen;
7623         param[ iBord ][ iNode ] = bordLength;
7624         nPrev = nCur;
7625       }
7626       // normalize within [0,1]
7627       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7628         param[ iBord ][ iNode ] /= bordLength;
7629       }
7630     }
7631
7632     // loop on border segments
7633     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7634     int i[ 2 ] = { 0, 0 };
7635     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7636     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7637
7638     TElemOfNodeListMap insertMap;
7639     TElemOfNodeListMap::iterator insertMapIt;
7640     // insertMap is
7641     // key:   elem to insert nodes into
7642     // value: 2 nodes to insert between + nodes to be inserted
7643     do {
7644       bool next[ 2 ] = { false, false };
7645
7646       // find min adjacent segment length after sewing
7647       double nextParam = 10., prevParam = 0;
7648       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7649         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7650           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7651         if ( i[ iBord ] > 0 )
7652           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7653       }
7654       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7655       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7656       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7657
7658       // choose to insert or to merge nodes
7659       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7660       if ( Abs( du ) <= minSegLen * 0.2 ) {
7661         // merge
7662         // ------
7663         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7664         const SMDS_MeshNode* n0 = *nIt[0];
7665         const SMDS_MeshNode* n1 = *nIt[1];
7666         nodeGroupsToMerge.back().push_back( n1 );
7667         nodeGroupsToMerge.back().push_back( n0 );
7668         // position of node of the border changes due to merge
7669         param[ 0 ][ i[0] ] += du;
7670         // move n1 for the sake of elem shape evaluation during insertion.
7671         // n1 will be removed by MergeNodes() anyway
7672         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
7673         next[0] = next[1] = true;
7674       }
7675       else {
7676         // insert
7677         // ------
7678         int intoBord = ( du < 0 ) ? 0 : 1;
7679         const SMDS_MeshElement* elem = *eIt[ intoBord ];
7680         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
7681         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
7682         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
7683         if ( intoBord == 1 ) {
7684           // move node of the border to be on a link of elem of the side
7685           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
7686           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
7687           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
7688           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
7689           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
7690         }
7691         insertMapIt = insertMap.find( elem );
7692         bool notFound = ( insertMapIt == insertMap.end() );
7693         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
7694         if ( otherLink ) {
7695           // insert into another link of the same element:
7696           // 1. perform insertion into the other link of the elem
7697           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7698           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
7699           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
7700           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
7701           // 2. perform insertion into the link of adjacent faces
7702           while (true) {
7703             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
7704             if ( adjElem )
7705               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
7706             else
7707               break;
7708           }
7709           if (toCreatePolyedrs) {
7710             // perform insertion into the links of adjacent volumes
7711             UpdateVolumes(n12, n22, nodeList);
7712           }
7713           // 3. find an element appeared on n1 and n2 after the insertion
7714           insertMap.erase( elem );
7715           elem = findAdjacentFace( n1, n2, 0 );
7716         }
7717         if ( notFound || otherLink ) {
7718           // add element and nodes of the side into the insertMap
7719           insertMapIt = insertMap.insert
7720             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
7721           (*insertMapIt).second.push_back( n1 );
7722           (*insertMapIt).second.push_back( n2 );
7723         }
7724         // add node to be inserted into elem
7725         (*insertMapIt).second.push_back( nIns );
7726         next[ 1 - intoBord ] = true;
7727       }
7728
7729       // go to the next segment
7730       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7731         if ( next[ iBord ] ) {
7732           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
7733             eIt[ iBord ]++;
7734           nPrev[ iBord ] = *nIt[ iBord ];
7735           nIt[ iBord ]++; i[ iBord ]++;
7736         }
7737       }
7738     }
7739     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
7740
7741     // perform insertion of nodes into elements
7742
7743     for (insertMapIt = insertMap.begin();
7744          insertMapIt != insertMap.end();
7745          insertMapIt++ )
7746     {
7747       const SMDS_MeshElement* elem = (*insertMapIt).first;
7748       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7749       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
7750       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
7751
7752       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
7753
7754       if ( !theSideIsFreeBorder ) {
7755         // look for and insert nodes into the faces adjacent to elem
7756         while (true) {
7757           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
7758           if ( adjElem )
7759             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
7760           else
7761             break;
7762         }
7763       }
7764       if (toCreatePolyedrs) {
7765         // perform insertion into the links of adjacent volumes
7766         UpdateVolumes(n1, n2, nodeList);
7767       }
7768     }
7769
7770     delete param[0];
7771     delete param[1];
7772   } // end: insert new nodes
7773
7774   MergeNodes ( nodeGroupsToMerge );
7775
7776   return aResult;
7777 }
7778
7779 //=======================================================================
7780 //function : InsertNodesIntoLink
7781 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
7782 //           and theBetweenNode2 and split theElement
7783 //=======================================================================
7784
7785 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
7786                                            const SMDS_MeshNode*        theBetweenNode1,
7787                                            const SMDS_MeshNode*        theBetweenNode2,
7788                                            list<const SMDS_MeshNode*>& theNodesToInsert,
7789                                            const bool                  toCreatePoly)
7790 {
7791   if ( theFace->GetType() != SMDSAbs_Face ) return;
7792
7793   // find indices of 2 link nodes and of the rest nodes
7794   int iNode = 0, il1, il2, i3, i4;
7795   il1 = il2 = i3 = i4 = -1;
7796   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
7797   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
7798
7799   if(theFace->IsQuadratic()) {
7800     const SMDS_VtkFace* F =
7801       dynamic_cast<const SMDS_VtkFace*>(theFace);
7802     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7803     // use special nodes iterator
7804     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7805     while( anIter->more() ) {
7806       const SMDS_MeshNode* n = cast2Node(anIter->next());
7807       if ( n == theBetweenNode1 )
7808         il1 = iNode;
7809       else if ( n == theBetweenNode2 )
7810         il2 = iNode;
7811       else if ( i3 < 0 )
7812         i3 = iNode;
7813       else
7814         i4 = iNode;
7815       nodes[ iNode++ ] = n;
7816     }
7817   }
7818   else {
7819     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7820     while ( nodeIt->more() ) {
7821       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7822       if ( n == theBetweenNode1 )
7823         il1 = iNode;
7824       else if ( n == theBetweenNode2 )
7825         il2 = iNode;
7826       else if ( i3 < 0 )
7827         i3 = iNode;
7828       else
7829         i4 = iNode;
7830       nodes[ iNode++ ] = n;
7831     }
7832   }
7833   if ( il1 < 0 || il2 < 0 || i3 < 0 )
7834     return ;
7835
7836   // arrange link nodes to go one after another regarding the face orientation
7837   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
7838   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
7839   if ( reverse ) {
7840     iNode = il1;
7841     il1 = il2;
7842     il2 = iNode;
7843     aNodesToInsert.reverse();
7844   }
7845   // check that not link nodes of a quadrangles are in good order
7846   int nbFaceNodes = theFace->NbNodes();
7847   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
7848     iNode = i3;
7849     i3 = i4;
7850     i4 = iNode;
7851   }
7852
7853   if (toCreatePoly || theFace->IsPoly()) {
7854
7855     iNode = 0;
7856     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
7857
7858     // add nodes of face up to first node of link
7859     bool isFLN = false;
7860
7861     if(theFace->IsQuadratic()) {
7862       const SMDS_VtkFace* F =
7863         dynamic_cast<const SMDS_VtkFace*>(theFace);
7864       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7865       // use special nodes iterator
7866       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7867       while( anIter->more()  && !isFLN ) {
7868         const SMDS_MeshNode* n = cast2Node(anIter->next());
7869         poly_nodes[iNode++] = n;
7870         if (n == nodes[il1]) {
7871           isFLN = true;
7872         }
7873       }
7874       // add nodes to insert
7875       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7876       for (; nIt != aNodesToInsert.end(); nIt++) {
7877         poly_nodes[iNode++] = *nIt;
7878       }
7879       // add nodes of face starting from last node of link
7880       while ( anIter->more() ) {
7881         poly_nodes[iNode++] = cast2Node(anIter->next());
7882       }
7883     }
7884     else {
7885       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7886       while ( nodeIt->more() && !isFLN ) {
7887         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7888         poly_nodes[iNode++] = n;
7889         if (n == nodes[il1]) {
7890           isFLN = true;
7891         }
7892       }
7893       // add nodes to insert
7894       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7895       for (; nIt != aNodesToInsert.end(); nIt++) {
7896         poly_nodes[iNode++] = *nIt;
7897       }
7898       // add nodes of face starting from last node of link
7899       while ( nodeIt->more() ) {
7900         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7901         poly_nodes[iNode++] = n;
7902       }
7903     }
7904
7905     // edit or replace the face
7906     SMESHDS_Mesh *aMesh = GetMeshDS();
7907
7908     if (theFace->IsPoly()) {
7909       aMesh->ChangePolygonNodes(theFace, poly_nodes);
7910     }
7911     else {
7912       int aShapeId = FindShape( theFace );
7913
7914       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7915       myLastCreatedElems.Append(newElem);
7916       if ( aShapeId && newElem )
7917         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7918
7919       aMesh->RemoveElement(theFace);
7920     }
7921     return;
7922   }
7923
7924   SMESHDS_Mesh *aMesh = GetMeshDS();
7925   if( !theFace->IsQuadratic() ) {
7926
7927     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
7928     int nbLinkNodes = 2 + aNodesToInsert.size();
7929     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
7930     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
7931     linkNodes[ 0 ] = nodes[ il1 ];
7932     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
7933     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7934     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7935       linkNodes[ iNode++ ] = *nIt;
7936     }
7937     // decide how to split a quadrangle: compare possible variants
7938     // and choose which of splits to be a quadrangle
7939     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
7940     if ( nbFaceNodes == 3 ) {
7941       iBestQuad = nbSplits;
7942       i4 = i3;
7943     }
7944     else if ( nbFaceNodes == 4 ) {
7945       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
7946       double aBestRate = DBL_MAX;
7947       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
7948         i1 = 0; i2 = 1;
7949         double aBadRate = 0;
7950         // evaluate elements quality
7951         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
7952           if ( iSplit == iQuad ) {
7953             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
7954                                    linkNodes[ i2++ ],
7955                                    nodes[ i3 ],
7956                                    nodes[ i4 ]);
7957             aBadRate += getBadRate( &quad, aCrit );
7958           }
7959           else {
7960             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
7961                                    linkNodes[ i2++ ],
7962                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
7963             aBadRate += getBadRate( &tria, aCrit );
7964           }
7965         }
7966         // choice
7967         if ( aBadRate < aBestRate ) {
7968           iBestQuad = iQuad;
7969           aBestRate = aBadRate;
7970         }
7971       }
7972     }
7973
7974     // create new elements
7975     int aShapeId = FindShape( theFace );
7976
7977     i1 = 0; i2 = 1;
7978     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
7979       SMDS_MeshElement* newElem = 0;
7980       if ( iSplit == iBestQuad )
7981         newElem = aMesh->AddFace (linkNodes[ i1++ ],
7982                                   linkNodes[ i2++ ],
7983                                   nodes[ i3 ],
7984                                   nodes[ i4 ]);
7985       else
7986         newElem = aMesh->AddFace (linkNodes[ i1++ ],
7987                                   linkNodes[ i2++ ],
7988                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
7989       myLastCreatedElems.Append(newElem);
7990       if ( aShapeId && newElem )
7991         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7992     }
7993
7994     // change nodes of theFace
7995     const SMDS_MeshNode* newNodes[ 4 ];
7996     newNodes[ 0 ] = linkNodes[ i1 ];
7997     newNodes[ 1 ] = linkNodes[ i2 ];
7998     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
7999     newNodes[ 3 ] = nodes[ i4 ];
8000     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8001     const SMDS_MeshElement* newElem = 0;
8002     if (iSplit == iBestQuad)
8003       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8004     else
8005       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8006     myLastCreatedElems.Append(newElem);
8007     if ( aShapeId && newElem )
8008       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8009 } // end if(!theFace->IsQuadratic())
8010   else { // theFace is quadratic
8011     // we have to split theFace on simple triangles and one simple quadrangle
8012     int tmp = il1/2;
8013     int nbshift = tmp*2;
8014     // shift nodes in nodes[] by nbshift
8015     int i,j;
8016     for(i=0; i<nbshift; i++) {
8017       const SMDS_MeshNode* n = nodes[0];
8018       for(j=0; j<nbFaceNodes-1; j++) {
8019         nodes[j] = nodes[j+1];
8020       }
8021       nodes[nbFaceNodes-1] = n;
8022     }
8023     il1 = il1 - nbshift;
8024     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8025     //   n0      n1     n2    n0      n1     n2
8026     //     +-----+-----+        +-----+-----+
8027     //      \         /         |           |
8028     //       \       /          |           |
8029     //      n5+     +n3       n7+           +n3
8030     //         \   /            |           |
8031     //          \ /             |           |
8032     //           +              +-----+-----+
8033     //           n4           n6      n5     n4
8034
8035     // create new elements
8036     int aShapeId = FindShape( theFace );
8037
8038     int n1,n2,n3;
8039     if(nbFaceNodes==6) { // quadratic triangle
8040       SMDS_MeshElement* newElem =
8041         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8042       myLastCreatedElems.Append(newElem);
8043       if ( aShapeId && newElem )
8044         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8045       if(theFace->IsMediumNode(nodes[il1])) {
8046         // create quadrangle
8047         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8048         myLastCreatedElems.Append(newElem);
8049         if ( aShapeId && newElem )
8050           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8051         n1 = 1;
8052         n2 = 2;
8053         n3 = 3;
8054       }
8055       else {
8056         // create quadrangle
8057         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8058         myLastCreatedElems.Append(newElem);
8059         if ( aShapeId && newElem )
8060           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8061         n1 = 0;
8062         n2 = 1;
8063         n3 = 5;
8064       }
8065     }
8066     else { // nbFaceNodes==8 - quadratic quadrangle
8067       SMDS_MeshElement* newElem =
8068         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8069       myLastCreatedElems.Append(newElem);
8070       if ( aShapeId && newElem )
8071         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8072       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8073       myLastCreatedElems.Append(newElem);
8074       if ( aShapeId && newElem )
8075         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8076       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8077       myLastCreatedElems.Append(newElem);
8078       if ( aShapeId && newElem )
8079         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8080       if(theFace->IsMediumNode(nodes[il1])) {
8081         // create quadrangle
8082         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8083         myLastCreatedElems.Append(newElem);
8084         if ( aShapeId && newElem )
8085           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8086         n1 = 1;
8087         n2 = 2;
8088         n3 = 3;
8089       }
8090       else {
8091         // create quadrangle
8092         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8093         myLastCreatedElems.Append(newElem);
8094         if ( aShapeId && newElem )
8095           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8096         n1 = 0;
8097         n2 = 1;
8098         n3 = 7;
8099       }
8100     }
8101     // create needed triangles using n1,n2,n3 and inserted nodes
8102     int nbn = 2 + aNodesToInsert.size();
8103     //const SMDS_MeshNode* aNodes[nbn];
8104     vector<const SMDS_MeshNode*> aNodes(nbn);
8105     aNodes[0] = nodes[n1];
8106     aNodes[nbn-1] = nodes[n2];
8107     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8108     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8109       aNodes[iNode++] = *nIt;
8110     }
8111     for(i=1; i<nbn; i++) {
8112       SMDS_MeshElement* newElem =
8113         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8114       myLastCreatedElems.Append(newElem);
8115       if ( aShapeId && newElem )
8116         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8117     }
8118   }
8119   // remove old face
8120   aMesh->RemoveElement(theFace);
8121 }
8122
8123 //=======================================================================
8124 //function : UpdateVolumes
8125 //purpose  :
8126 //=======================================================================
8127 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8128                                       const SMDS_MeshNode*        theBetweenNode2,
8129                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8130 {
8131   myLastCreatedElems.Clear();
8132   myLastCreatedNodes.Clear();
8133
8134   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8135   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8136     const SMDS_MeshElement* elem = invElemIt->next();
8137
8138     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8139     SMDS_VolumeTool aVolume (elem);
8140     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8141       continue;
8142
8143     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8144     int iface, nbFaces = aVolume.NbFaces();
8145     vector<const SMDS_MeshNode *> poly_nodes;
8146     vector<int> quantities (nbFaces);
8147
8148     for (iface = 0; iface < nbFaces; iface++) {
8149       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8150       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8151       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8152
8153       for (int inode = 0; inode < nbFaceNodes; inode++) {
8154         poly_nodes.push_back(faceNodes[inode]);
8155
8156         if (nbInserted == 0) {
8157           if (faceNodes[inode] == theBetweenNode1) {
8158             if (faceNodes[inode + 1] == theBetweenNode2) {
8159               nbInserted = theNodesToInsert.size();
8160
8161               // add nodes to insert
8162               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8163               for (; nIt != theNodesToInsert.end(); nIt++) {
8164                 poly_nodes.push_back(*nIt);
8165               }
8166             }
8167           }
8168           else if (faceNodes[inode] == theBetweenNode2) {
8169             if (faceNodes[inode + 1] == theBetweenNode1) {
8170               nbInserted = theNodesToInsert.size();
8171
8172               // add nodes to insert in reversed order
8173               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8174               nIt--;
8175               for (; nIt != theNodesToInsert.begin(); nIt--) {
8176                 poly_nodes.push_back(*nIt);
8177               }
8178               poly_nodes.push_back(*nIt);
8179             }
8180           }
8181           else {
8182           }
8183         }
8184       }
8185       quantities[iface] = nbFaceNodes + nbInserted;
8186     }
8187
8188     // Replace or update the volume
8189     SMESHDS_Mesh *aMesh = GetMeshDS();
8190
8191     if (elem->IsPoly()) {
8192       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8193
8194     }
8195     else {
8196       int aShapeId = FindShape( elem );
8197
8198       SMDS_MeshElement* newElem =
8199         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8200       myLastCreatedElems.Append(newElem);
8201       if (aShapeId && newElem)
8202         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8203
8204       aMesh->RemoveElement(elem);
8205     }
8206   }
8207 }
8208
8209 namespace
8210 {
8211   //================================================================================
8212   /*!
8213    * \brief Transform any volume into data of SMDSEntity_Polyhedra
8214    */
8215   //================================================================================
8216
8217   void volumeToPolyhedron( const SMDS_MeshElement*         elem,
8218                            vector<const SMDS_MeshNode *> & nodes,
8219                            vector<int> &                   nbNodeInFaces )
8220   {
8221     nodes.clear();
8222     nbNodeInFaces.clear();
8223     SMDS_VolumeTool vTool ( elem );
8224     for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
8225     {
8226       const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
8227       nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
8228       nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
8229     }
8230   }
8231 }
8232
8233 //=======================================================================
8234 /*!
8235  * \brief Convert elements contained in a submesh to quadratic
8236  * \return int - nb of checked elements
8237  */
8238 //=======================================================================
8239
8240 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8241                                              SMESH_MesherHelper& theHelper,
8242                                              const bool          theForce3d)
8243 {
8244   int nbElem = 0;
8245   if( !theSm ) return nbElem;
8246
8247   vector<int> nbNodeInFaces;
8248   vector<const SMDS_MeshNode *> nodes;
8249   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8250   while(ElemItr->more())
8251   {
8252     nbElem++;
8253     const SMDS_MeshElement* elem = ElemItr->next();
8254     if( !elem ) continue;
8255
8256     // analyse a necessity of conversion
8257     const SMDSAbs_ElementType aType = elem->GetType();
8258     if ( aType < SMDSAbs_Edge || aType > SMDSAbs_Volume )
8259       continue;
8260     const SMDSAbs_EntityType aGeomType = elem->GetEntityType();
8261     bool hasCentralNodes = false;
8262     if ( elem->IsQuadratic() )
8263     {
8264       bool alreadyOK;
8265       switch ( aGeomType ) {
8266       case SMDSEntity_Quad_Triangle:
8267       case SMDSEntity_Quad_Quadrangle:
8268       case SMDSEntity_Quad_Hexa:
8269         alreadyOK = !theHelper.GetIsBiQuadratic(); break;
8270
8271       case SMDSEntity_BiQuad_Triangle:
8272       case SMDSEntity_BiQuad_Quadrangle:
8273       case SMDSEntity_TriQuad_Hexa:
8274         alreadyOK = theHelper.GetIsBiQuadratic();
8275         hasCentralNodes = true;
8276         break;
8277       default:
8278         alreadyOK = true;
8279       }
8280       // take into account already present modium nodes
8281       switch ( aType ) {
8282       case SMDSAbs_Volume:
8283         theHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( elem )); break;
8284       case SMDSAbs_Face:
8285         theHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem )); break;
8286       case SMDSAbs_Edge:
8287         theHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( elem )); break;
8288       default:;
8289       }
8290       if ( alreadyOK )
8291         continue;
8292     }
8293     // get elem data needed to re-create it
8294     //
8295     const int id      = elem->GetID();
8296     const int nbNodes = elem->NbCornerNodes();
8297     nodes.assign(elem->begin_nodes(), elem->end_nodes());
8298     if ( aGeomType == SMDSEntity_Polyhedra )
8299       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
8300     else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
8301       volumeToPolyhedron( elem, nodes, nbNodeInFaces );
8302
8303     // remove a linear element
8304     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
8305
8306     // remove central nodes of biquadratic elements (biquad->quad convertion)
8307     if ( hasCentralNodes )
8308       for ( size_t i = nbNodes * 2; i < nodes.size(); ++i )
8309         if ( nodes[i]->NbInverseElements() == 0 )
8310           GetMeshDS()->RemoveFreeNode( nodes[i], theSm, /*fromGroups=*/true );
8311
8312     const SMDS_MeshElement* NewElem = 0;
8313
8314     switch( aType )
8315     {
8316     case SMDSAbs_Edge :
8317       {
8318         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8319         break;
8320       }
8321     case SMDSAbs_Face :
8322       {
8323         switch(nbNodes)
8324         {
8325         case 3:
8326           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8327           break;
8328         case 4:
8329           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8330           break;
8331         default:
8332           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
8333         }
8334         break;
8335       }
8336     case SMDSAbs_Volume :
8337       {
8338         switch( aGeomType )
8339         {
8340         case SMDSEntity_Tetra:
8341           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8342           break;
8343         case SMDSEntity_Pyramid:
8344           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
8345           break;
8346         case SMDSEntity_Penta:
8347           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
8348           break;
8349         case SMDSEntity_Hexa:
8350         case SMDSEntity_Quad_Hexa:
8351         case SMDSEntity_TriQuad_Hexa:
8352           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8353                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8354           break;
8355         case SMDSEntity_Hexagonal_Prism:
8356         default:
8357           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8358         }
8359         break;
8360       }
8361     default :
8362       continue;
8363     }
8364     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8365     if( NewElem && NewElem->getshapeId() < 1 )
8366       theSm->AddElement( NewElem );
8367   }
8368   return nbElem;
8369 }
8370 //=======================================================================
8371 //function : ConvertToQuadratic
8372 //purpose  :
8373 //=======================================================================
8374
8375 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad)
8376 {
8377   SMESHDS_Mesh* meshDS = GetMeshDS();
8378
8379   SMESH_MesherHelper aHelper(*myMesh);
8380
8381   aHelper.SetIsQuadratic( true );
8382   aHelper.SetIsBiQuadratic( theToBiQuad );
8383   aHelper.SetElementsOnShape(true);
8384
8385   // convert elements assigned to sub-meshes
8386   int nbCheckedElems = 0;
8387   if ( myMesh->HasShapeToMesh() )
8388   {
8389     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8390     {
8391       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8392       while ( smIt->more() ) {
8393         SMESH_subMesh* sm = smIt->next();
8394         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8395           aHelper.SetSubShape( sm->GetSubShape() );
8396           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8397         }
8398       }
8399     }
8400   }
8401
8402   // convert elements NOT assigned to sub-meshes
8403   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8404   if ( nbCheckedElems < totalNbElems ) // not all elements are in sub-meshes
8405   {
8406     aHelper.SetElementsOnShape(false);
8407     SMESHDS_SubMesh *smDS = 0;
8408
8409     // convert edges
8410     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8411     while( aEdgeItr->more() )
8412     {
8413       const SMDS_MeshEdge* edge = aEdgeItr->next();
8414       if ( !edge->IsQuadratic() )
8415       {
8416         int                  id = edge->GetID();
8417         const SMDS_MeshNode* n1 = edge->GetNode(0);
8418         const SMDS_MeshNode* n2 = edge->GetNode(1);
8419
8420         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
8421
8422         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8423         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8424       }
8425       else
8426       {
8427         aHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( edge ));
8428       }
8429     }
8430
8431     // convert faces
8432     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8433     while( aFaceItr->more() )
8434     {
8435       const SMDS_MeshFace* face = aFaceItr->next();
8436       if ( !face ) continue;
8437       
8438       const SMDSAbs_EntityType type = face->GetEntityType();
8439       bool alreadyOK;
8440       switch( type )
8441       {
8442       case SMDSEntity_Quad_Triangle:
8443       case SMDSEntity_Quad_Quadrangle:
8444         alreadyOK = !theToBiQuad;
8445         aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
8446         break;
8447       case SMDSEntity_BiQuad_Triangle:
8448       case SMDSEntity_BiQuad_Quadrangle:
8449         alreadyOK = theToBiQuad;
8450         aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
8451         break;
8452       default: alreadyOK = false;
8453       }
8454       if ( alreadyOK )
8455         continue;
8456
8457       const int id = face->GetID();
8458       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
8459
8460       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
8461
8462       SMDS_MeshFace * NewFace = 0;
8463       switch( type )
8464       {
8465       case SMDSEntity_Triangle:
8466       case SMDSEntity_Quad_Triangle:
8467       case SMDSEntity_BiQuad_Triangle:
8468         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8469         if ( nodes.size() == 7 && nodes[6]->NbInverseElements() == 0 ) // rm a central node
8470           GetMeshDS()->RemoveFreeNode( nodes[6], /*sm=*/0, /*fromGroups=*/true );
8471         break;
8472
8473       case SMDSEntity_Quadrangle:
8474       case SMDSEntity_Quad_Quadrangle:
8475       case SMDSEntity_BiQuad_Quadrangle:
8476         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8477         if ( nodes.size() == 9 && nodes[8]->NbInverseElements() == 0 ) // rm a central node
8478           GetMeshDS()->RemoveFreeNode( nodes[8], /*sm=*/0, /*fromGroups=*/true );
8479         break;
8480
8481       default:;
8482         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
8483       }
8484       ReplaceElemInGroups( face, NewFace, GetMeshDS());
8485     }
8486
8487     // convert volumes
8488     vector<int> nbNodeInFaces;
8489     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8490     while(aVolumeItr->more())
8491     {
8492       const SMDS_MeshVolume* volume = aVolumeItr->next();
8493       if ( !volume ) continue;
8494
8495       const SMDSAbs_EntityType type = volume->GetEntityType();
8496       if (( theToBiQuad  && type == SMDSEntity_TriQuad_Hexa ) ||
8497           ( !theToBiQuad && type == SMDSEntity_Quad_Hexa ))
8498       {
8499         aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume ));
8500         continue;
8501       }
8502       const int id = volume->GetID();
8503       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
8504       if ( type == SMDSEntity_Polyhedra )
8505         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
8506       else if ( type == SMDSEntity_Hexagonal_Prism )
8507         volumeToPolyhedron( volume, nodes, nbNodeInFaces );
8508
8509       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
8510
8511       SMDS_MeshVolume * NewVolume = 0;
8512       switch ( type )
8513       {
8514       case SMDSEntity_Tetra:
8515         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
8516         break;
8517       case SMDSEntity_Hexa:
8518       case SMDSEntity_Quad_Hexa:
8519       case SMDSEntity_TriQuad_Hexa:
8520         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8521                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8522         for ( size_t i = 20; i < nodes.size(); ++i ) // rm central nodes
8523           if ( nodes[i]->NbInverseElements() == 0 )
8524             GetMeshDS()->RemoveFreeNode( nodes[i], /*sm=*/0, /*fromGroups=*/true );
8525         break;
8526       case SMDSEntity_Pyramid:
8527         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8528                                       nodes[3], nodes[4], id, theForce3d);
8529         break;
8530       case SMDSEntity_Penta:
8531         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8532                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
8533         break;
8534       case SMDSEntity_Hexagonal_Prism:
8535       default:
8536         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8537       }
8538       ReplaceElemInGroups(volume, NewVolume, meshDS);
8539     }
8540   }
8541
8542   if ( !theForce3d )
8543   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8544     // aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8545     // aHelper.FixQuadraticElements(myError);
8546     SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
8547   }
8548 }
8549
8550 //================================================================================
8551 /*!
8552  * \brief Makes given elements quadratic
8553  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
8554  *  \param theElements - elements to make quadratic
8555  */
8556 //================================================================================
8557
8558 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
8559                                           TIDSortedElemSet& theElements,
8560                                           const bool        theToBiQuad)
8561 {
8562   if ( theElements.empty() ) return;
8563
8564   // we believe that all theElements are of the same type
8565   const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
8566
8567   // get all nodes shared by theElements
8568   TIDSortedNodeSet allNodes;
8569   TIDSortedElemSet::iterator eIt = theElements.begin();
8570   for ( ; eIt != theElements.end(); ++eIt )
8571     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
8572
8573   // complete theElements with elements of lower dim whose all nodes are in allNodes
8574
8575   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
8576   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
8577   TIDSortedNodeSet::iterator nIt = allNodes.begin();
8578   for ( ; nIt != allNodes.end(); ++nIt )
8579   {
8580     const SMDS_MeshNode* n = *nIt;
8581     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
8582     while ( invIt->more() )
8583     {
8584       const SMDS_MeshElement*      e = invIt->next();
8585       const SMDSAbs_ElementType type = e->GetType();
8586       if ( e->IsQuadratic() )
8587       {
8588         quadAdjacentElems[ type ].insert( e );
8589
8590         bool alreadyOK;
8591         switch ( e->GetEntityType() ) {
8592         case SMDSEntity_Quad_Triangle:
8593         case SMDSEntity_Quad_Quadrangle:
8594         case SMDSEntity_Quad_Hexa:         alreadyOK = !theToBiQuad; break;
8595         case SMDSEntity_BiQuad_Triangle:
8596         case SMDSEntity_BiQuad_Quadrangle:
8597         case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; break;
8598         default:                           alreadyOK = true;
8599         }
8600         if ( alreadyOK )
8601           continue;
8602       }
8603       if ( type >= elemType )
8604         continue; // same type or more complex linear element
8605
8606       if ( !checkedAdjacentElems[ type ].insert( e ).second )
8607         continue; // e is already checked
8608
8609       // check nodes
8610       bool allIn = true;
8611       SMDS_NodeIteratorPtr nodeIt = e->nodeIterator();
8612       while ( nodeIt->more() && allIn )
8613         allIn = allNodes.count( nodeIt->next() );
8614       if ( allIn )
8615         theElements.insert(e );
8616     }
8617   }
8618
8619   SMESH_MesherHelper helper(*myMesh);
8620   helper.SetIsQuadratic( true );
8621   helper.SetIsBiQuadratic( theToBiQuad );
8622
8623   // add links of quadratic adjacent elements to the helper
8624
8625   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
8626     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
8627           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
8628     {
8629       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
8630     }
8631   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
8632     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
8633           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
8634     {
8635       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
8636     }
8637   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
8638     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
8639           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
8640     {
8641       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
8642     }
8643
8644   // make quadratic (or bi-tri-quadratic) elements instead of linear ones
8645
8646   SMESHDS_Mesh*  meshDS = GetMeshDS();
8647   SMESHDS_SubMesh* smDS = 0;
8648   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
8649   {
8650     const SMDS_MeshElement* elem = *eIt;
8651
8652     bool alreadyOK;
8653     int nbCentralNodes = 0;
8654     switch ( elem->GetEntityType() ) {
8655       // linear convertible
8656     case SMDSEntity_Edge:
8657     case SMDSEntity_Triangle:
8658     case SMDSEntity_Quadrangle:
8659     case SMDSEntity_Tetra:
8660     case SMDSEntity_Pyramid:
8661     case SMDSEntity_Hexa:
8662     case SMDSEntity_Penta:             alreadyOK = false;       nbCentralNodes = 0; break;
8663       // quadratic that can become bi-quadratic
8664     case SMDSEntity_Quad_Triangle:
8665     case SMDSEntity_Quad_Quadrangle:
8666     case SMDSEntity_Quad_Hexa:         alreadyOK =!theToBiQuad; nbCentralNodes = 0; break;
8667       // bi-quadratic
8668     case SMDSEntity_BiQuad_Triangle:
8669     case SMDSEntity_BiQuad_Quadrangle: alreadyOK = theToBiQuad; nbCentralNodes = 1; break;
8670     case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; nbCentralNodes = 7; break;
8671       // the rest
8672     default:                           alreadyOK = true;
8673     }
8674     if ( alreadyOK ) continue;
8675
8676     const SMDSAbs_ElementType type = elem->GetType();
8677     const int                   id = elem->GetID();
8678     const int              nbNodes = elem->NbCornerNodes();
8679     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
8680
8681     helper.SetSubShape( elem->getshapeId() );
8682
8683     if ( !smDS || !smDS->Contains( elem ))
8684       smDS = meshDS->MeshElements( elem->getshapeId() );
8685     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
8686
8687     SMDS_MeshElement * newElem = 0;
8688     switch( nbNodes )
8689     {
8690     case 4: // cases for most frequently used element types go first (for optimization)
8691       if ( type == SMDSAbs_Volume )
8692         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8693       else
8694         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8695       break;
8696     case 8:
8697       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8698                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8699       break;
8700     case 3:
8701       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
8702       break;
8703     case 2:
8704       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8705       break;
8706     case 5:
8707       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8708                                  nodes[4], id, theForce3d);
8709       break;
8710     case 6:
8711       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8712                                  nodes[4], nodes[5], id, theForce3d);
8713       break;
8714     default:;
8715     }
8716     ReplaceElemInGroups( elem, newElem, meshDS);
8717     if( newElem && smDS )
8718       smDS->AddElement( newElem );
8719
8720      // remove central nodes
8721     for ( size_t i = nodes.size() - nbCentralNodes; i < nodes.size(); ++i )
8722       if ( nodes[i]->NbInverseElements() == 0 )
8723         meshDS->RemoveFreeNode( nodes[i], smDS, /*fromGroups=*/true );
8724
8725   } // loop on theElements
8726
8727   if ( !theForce3d )
8728   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8729     // helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8730     // helper.FixQuadraticElements( myError );
8731     SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
8732   }
8733 }
8734
8735 //=======================================================================
8736 /*!
8737  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8738  * \return int - nb of checked elements
8739  */
8740 //=======================================================================
8741
8742 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
8743                                      SMDS_ElemIteratorPtr theItr,
8744                                      const int            theShapeID)
8745 {
8746   int nbElem = 0;
8747   SMESHDS_Mesh* meshDS = GetMeshDS();
8748
8749   while( theItr->more() )
8750   {
8751     const SMDS_MeshElement* elem = theItr->next();
8752     nbElem++;
8753     if( elem && elem->IsQuadratic())
8754     {
8755       int id                    = elem->GetID();
8756       int nbCornerNodes         = elem->NbCornerNodes();
8757       SMDSAbs_ElementType aType = elem->GetType();
8758
8759       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
8760
8761       //remove a quadratic element
8762       if ( !theSm || !theSm->Contains( elem ))
8763         theSm = meshDS->MeshElements( elem->getshapeId() );
8764       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
8765
8766       // remove medium nodes
8767       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
8768         if ( nodes[i]->NbInverseElements() == 0 )
8769           meshDS->RemoveFreeNode( nodes[i], theSm );
8770
8771       // add a linear element
8772       nodes.resize( nbCornerNodes );
8773       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
8774       ReplaceElemInGroups(elem, newElem, meshDS);
8775       if( theSm && newElem )
8776         theSm->AddElement( newElem );
8777     }
8778   }
8779   return nbElem;
8780 }
8781
8782 //=======================================================================
8783 //function : ConvertFromQuadratic
8784 //purpose  :
8785 //=======================================================================
8786
8787 bool SMESH_MeshEditor::ConvertFromQuadratic()
8788 {
8789   int nbCheckedElems = 0;
8790   if ( myMesh->HasShapeToMesh() )
8791   {
8792     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8793     {
8794       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8795       while ( smIt->more() ) {
8796         SMESH_subMesh* sm = smIt->next();
8797         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8798           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8799       }
8800     }
8801   }
8802
8803   int totalNbElems =
8804     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8805   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8806   {
8807     SMESHDS_SubMesh *aSM = 0;
8808     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8809   }
8810
8811   return true;
8812 }
8813
8814 namespace
8815 {
8816   //================================================================================
8817   /*!
8818    * \brief Return true if all medium nodes of the element are in the node set
8819    */
8820   //================================================================================
8821
8822   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
8823   {
8824     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
8825       if ( !nodeSet.count( elem->GetNode(i) ))
8826         return false;
8827     return true;
8828   }
8829 }
8830
8831 //================================================================================
8832 /*!
8833  * \brief Makes given elements linear
8834  */
8835 //================================================================================
8836
8837 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
8838 {
8839   if ( theElements.empty() ) return;
8840
8841   // collect IDs of medium nodes of theElements; some of these nodes will be removed
8842   set<int> mediumNodeIDs;
8843   TIDSortedElemSet::iterator eIt = theElements.begin();
8844   for ( ; eIt != theElements.end(); ++eIt )
8845   {
8846     const SMDS_MeshElement* e = *eIt;
8847     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
8848       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
8849   }
8850
8851   // replace given elements by linear ones
8852   SMDS_ElemIteratorPtr elemIt = elemSetIterator( theElements );
8853   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
8854
8855   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
8856   // except those elements sharing medium nodes of quadratic element whose medium nodes
8857   // are not all in mediumNodeIDs
8858
8859   // get remaining medium nodes
8860   TIDSortedNodeSet mediumNodes;
8861   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
8862   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
8863     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
8864       mediumNodes.insert( mediumNodes.end(), n );
8865
8866   // find more quadratic elements to convert
8867   TIDSortedElemSet moreElemsToConvert;
8868   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
8869   for ( ; nIt != mediumNodes.end(); ++nIt )
8870   {
8871     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
8872     while ( invIt->more() )
8873     {
8874       const SMDS_MeshElement* e = invIt->next();
8875       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
8876       {
8877         // find a more complex element including e and
8878         // whose medium nodes are not in mediumNodes
8879         bool complexFound = false;
8880         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
8881         {
8882           SMDS_ElemIteratorPtr invIt2 =
8883             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
8884           while ( invIt2->more() )
8885           {
8886             const SMDS_MeshElement* eComplex = invIt2->next();
8887             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
8888             {
8889               int nbCommonNodes = SMESH_MeshAlgos::GetCommonNodes( e, eComplex ).size();
8890               if ( nbCommonNodes == e->NbNodes())
8891               {
8892                 complexFound = true;
8893                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
8894                 break;
8895               }
8896             }
8897           }
8898         }
8899         if ( !complexFound )
8900           moreElemsToConvert.insert( e );
8901       }
8902     }
8903   }
8904   elemIt = elemSetIterator( moreElemsToConvert );
8905   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
8906 }
8907
8908 //=======================================================================
8909 //function : SewSideElements
8910 //purpose  :
8911 //=======================================================================
8912
8913 SMESH_MeshEditor::Sew_Error
8914 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
8915                                    TIDSortedElemSet&    theSide2,
8916                                    const SMDS_MeshNode* theFirstNode1,
8917                                    const SMDS_MeshNode* theFirstNode2,
8918                                    const SMDS_MeshNode* theSecondNode1,
8919                                    const SMDS_MeshNode* theSecondNode2)
8920 {
8921   myLastCreatedElems.Clear();
8922   myLastCreatedNodes.Clear();
8923
8924   MESSAGE ("::::SewSideElements()");
8925   if ( theSide1.size() != theSide2.size() )
8926     return SEW_DIFF_NB_OF_ELEMENTS;
8927
8928   Sew_Error aResult = SEW_OK;
8929   // Algo:
8930   // 1. Build set of faces representing each side
8931   // 2. Find which nodes of the side 1 to merge with ones on the side 2
8932   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8933
8934   // =======================================================================
8935   // 1. Build set of faces representing each side:
8936   // =======================================================================
8937   // a. build set of nodes belonging to faces
8938   // b. complete set of faces: find missing faces whose nodes are in set of nodes
8939   // c. create temporary faces representing side of volumes if correspondent
8940   //    face does not exist
8941
8942   SMESHDS_Mesh* aMesh = GetMeshDS();
8943   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
8944   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
8945   TIDSortedElemSet             faceSet1, faceSet2;
8946   set<const SMDS_MeshElement*> volSet1,  volSet2;
8947   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
8948   TIDSortedElemSet             * faceSetPtr[] = { &faceSet1, &faceSet2 };
8949   set<const SMDS_MeshElement*> *  volSetPtr[] = { &volSet1,  &volSet2  };
8950   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
8951   TIDSortedElemSet             * elemSetPtr[] = { &theSide1, &theSide2 };
8952   int iSide, iFace, iNode;
8953
8954   list<const SMDS_MeshElement* > tempFaceList;
8955   for ( iSide = 0; iSide < 2; iSide++ ) {
8956     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
8957     TIDSortedElemSet             * elemSet = elemSetPtr[ iSide ];
8958     TIDSortedElemSet             * faceSet = faceSetPtr[ iSide ];
8959     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
8960     set<const SMDS_MeshElement*>::iterator vIt;
8961     TIDSortedElemSet::iterator eIt;
8962     set<const SMDS_MeshNode*>::iterator    nIt;
8963
8964     // check that given nodes belong to given elements
8965     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
8966     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
8967     int firstIndex = -1, secondIndex = -1;
8968     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8969       const SMDS_MeshElement* elem = *eIt;
8970       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
8971       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
8972       if ( firstIndex > -1 && secondIndex > -1 ) break;
8973     }
8974     if ( firstIndex < 0 || secondIndex < 0 ) {
8975       // we can simply return until temporary faces created
8976       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
8977     }
8978
8979     // -----------------------------------------------------------
8980     // 1a. Collect nodes of existing faces
8981     //     and build set of face nodes in order to detect missing
8982     //     faces corresponding to sides of volumes
8983     // -----------------------------------------------------------
8984
8985     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
8986
8987     // loop on the given element of a side
8988     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8989       //const SMDS_MeshElement* elem = *eIt;
8990       const SMDS_MeshElement* elem = *eIt;
8991       if ( elem->GetType() == SMDSAbs_Face ) {
8992         faceSet->insert( elem );
8993         set <const SMDS_MeshNode*> faceNodeSet;
8994         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
8995         while ( nodeIt->more() ) {
8996           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8997           nodeSet->insert( n );
8998           faceNodeSet.insert( n );
8999         }
9000         setOfFaceNodeSet.insert( faceNodeSet );
9001       }
9002       else if ( elem->GetType() == SMDSAbs_Volume )
9003         volSet->insert( elem );
9004     }
9005     // ------------------------------------------------------------------------------
9006     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9007     // ------------------------------------------------------------------------------
9008
9009     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9010       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9011       while ( fIt->more() ) { // loop on faces sharing a node
9012         const SMDS_MeshElement* f = fIt->next();
9013         if ( faceSet->find( f ) == faceSet->end() ) {
9014           // check if all nodes are in nodeSet and
9015           // complete setOfFaceNodeSet if they are
9016           set <const SMDS_MeshNode*> faceNodeSet;
9017           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9018           bool allInSet = true;
9019           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9020             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9021             if ( nodeSet->find( n ) == nodeSet->end() )
9022               allInSet = false;
9023             else
9024               faceNodeSet.insert( n );
9025           }
9026           if ( allInSet ) {
9027             faceSet->insert( f );
9028             setOfFaceNodeSet.insert( faceNodeSet );
9029           }
9030         }
9031       }
9032     }
9033
9034     // -------------------------------------------------------------------------
9035     // 1c. Create temporary faces representing sides of volumes if correspondent
9036     //     face does not exist
9037     // -------------------------------------------------------------------------
9038
9039     if ( !volSet->empty() ) {
9040       //int nodeSetSize = nodeSet->size();
9041
9042       // loop on given volumes
9043       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9044         SMDS_VolumeTool vol (*vIt);
9045         // loop on volume faces: find free faces
9046         // --------------------------------------
9047         list<const SMDS_MeshElement* > freeFaceList;
9048         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9049           if ( !vol.IsFreeFace( iFace ))
9050             continue;
9051           // check if there is already a face with same nodes in a face set
9052           const SMDS_MeshElement* aFreeFace = 0;
9053           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9054           int nbNodes = vol.NbFaceNodes( iFace );
9055           set <const SMDS_MeshNode*> faceNodeSet;
9056           vol.GetFaceNodes( iFace, faceNodeSet );
9057           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9058           if ( isNewFace ) {
9059             // no such a face is given but it still can exist, check it
9060             vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
9061             aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
9062           }
9063           if ( !aFreeFace ) {
9064             // create a temporary face
9065             if ( nbNodes == 3 ) {
9066               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9067               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9068             }
9069             else if ( nbNodes == 4 ) {
9070               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9071               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9072             }
9073             else {
9074               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9075               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9076               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9077             }
9078             if ( aFreeFace )
9079               tempFaceList.push_back( aFreeFace );
9080           }
9081
9082           if ( aFreeFace )
9083             freeFaceList.push_back( aFreeFace );
9084
9085         } // loop on faces of a volume
9086
9087         // choose one of several free faces of a volume
9088         // --------------------------------------------
9089         if ( freeFaceList.size() > 1 ) {
9090           // choose a face having max nb of nodes shared by other elems of a side
9091           int maxNbNodes = -1;
9092           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9093           while ( fIt != freeFaceList.end() ) { // loop on free faces
9094             int nbSharedNodes = 0;
9095             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9096             while ( nodeIt->more() ) { // loop on free face nodes
9097               const SMDS_MeshNode* n =
9098                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9099               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9100               while ( invElemIt->more() ) {
9101                 const SMDS_MeshElement* e = invElemIt->next();
9102                 nbSharedNodes += faceSet->count( e );
9103                 nbSharedNodes += elemSet->count( e );
9104               }
9105             }
9106             if ( nbSharedNodes > maxNbNodes ) {
9107               maxNbNodes = nbSharedNodes;
9108               freeFaceList.erase( freeFaceList.begin(), fIt++ );
9109             }
9110             else if ( nbSharedNodes == maxNbNodes ) {
9111               fIt++;
9112             }
9113             else {
9114               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9115             }
9116           }
9117           if ( freeFaceList.size() > 1 )
9118           {
9119             // could not choose one face, use another way
9120             // choose a face most close to the bary center of the opposite side
9121             gp_XYZ aBC( 0., 0., 0. );
9122             set <const SMDS_MeshNode*> addedNodes;
9123             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9124             eIt = elemSet2->begin();
9125             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9126               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9127               while ( nodeIt->more() ) { // loop on free face nodes
9128                 const SMDS_MeshNode* n =
9129                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9130                 if ( addedNodes.insert( n ).second )
9131                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9132               }
9133             }
9134             aBC /= addedNodes.size();
9135             double minDist = DBL_MAX;
9136             fIt = freeFaceList.begin();
9137             while ( fIt != freeFaceList.end() ) { // loop on free faces
9138               double dist = 0;
9139               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9140               while ( nodeIt->more() ) { // loop on free face nodes
9141                 const SMDS_MeshNode* n =
9142                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9143                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9144                 dist += ( aBC - p ).SquareModulus();
9145               }
9146               if ( dist < minDist ) {
9147                 minDist = dist;
9148                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9149               }
9150               else
9151                 fIt = freeFaceList.erase( fIt++ );
9152             }
9153           }
9154         } // choose one of several free faces of a volume
9155
9156         if ( freeFaceList.size() == 1 ) {
9157           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9158           faceSet->insert( aFreeFace );
9159           // complete a node set with nodes of a found free face
9160           //           for ( iNode = 0; iNode < ; iNode++ )
9161           //             nodeSet->insert( fNodes[ iNode ] );
9162         }
9163
9164       } // loop on volumes of a side
9165
9166       //       // complete a set of faces if new nodes in a nodeSet appeared
9167       //       // ----------------------------------------------------------
9168       //       if ( nodeSetSize != nodeSet->size() ) {
9169       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9170       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9171       //           while ( fIt->more() ) { // loop on faces sharing a node
9172       //             const SMDS_MeshElement* f = fIt->next();
9173       //             if ( faceSet->find( f ) == faceSet->end() ) {
9174       //               // check if all nodes are in nodeSet and
9175       //               // complete setOfFaceNodeSet if they are
9176       //               set <const SMDS_MeshNode*> faceNodeSet;
9177       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9178       //               bool allInSet = true;
9179       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9180       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9181       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9182       //                   allInSet = false;
9183       //                 else
9184       //                   faceNodeSet.insert( n );
9185       //               }
9186       //               if ( allInSet ) {
9187       //                 faceSet->insert( f );
9188       //                 setOfFaceNodeSet.insert( faceNodeSet );
9189       //               }
9190       //             }
9191       //           }
9192       //         }
9193       //       }
9194     } // Create temporary faces, if there are volumes given
9195   } // loop on sides
9196
9197   if ( faceSet1.size() != faceSet2.size() ) {
9198     // delete temporary faces: they are in reverseElements of actual nodes
9199 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9200 //    while ( tmpFaceIt->more() )
9201 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9202 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9203 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9204 //      aMesh->RemoveElement(*tmpFaceIt);
9205     MESSAGE("Diff nb of faces");
9206     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9207   }
9208
9209   // ============================================================
9210   // 2. Find nodes to merge:
9211   //              bind a node to remove to a node to put instead
9212   // ============================================================
9213
9214   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9215   if ( theFirstNode1 != theFirstNode2 )
9216     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9217   if ( theSecondNode1 != theSecondNode2 )
9218     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9219
9220   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9221   set< long > linkIdSet; // links to process
9222   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9223
9224   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9225   list< NLink > linkList[2];
9226   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9227   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9228   // loop on links in linkList; find faces by links and append links
9229   // of the found faces to linkList
9230   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9231   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
9232   {
9233     NLink link[] = { *linkIt[0], *linkIt[1] };
9234     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9235     if ( !linkIdSet.count( linkID ) )
9236       continue;
9237
9238     // by links, find faces in the face sets,
9239     // and find indices of link nodes in the found faces;
9240     // in a face set, there is only one or no face sharing a link
9241     // ---------------------------------------------------------------
9242
9243     const SMDS_MeshElement* face[] = { 0, 0 };
9244     vector<const SMDS_MeshNode*> fnodes[2];
9245     int iLinkNode[2][2];
9246     TIDSortedElemSet avoidSet;
9247     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9248       const SMDS_MeshNode* n1 = link[iSide].first;
9249       const SMDS_MeshNode* n2 = link[iSide].second;
9250       //cout << "Side " << iSide << " ";
9251       //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
9252       // find a face by two link nodes
9253       face[ iSide ] = SMESH_MeshAlgos::FindFaceInSet( n1, n2,
9254                                                       *faceSetPtr[ iSide ], avoidSet,
9255                                                       &iLinkNode[iSide][0],
9256                                                       &iLinkNode[iSide][1] );
9257       if ( face[ iSide ])
9258       {
9259         //cout << " F " << face[ iSide]->GetID() <<endl;
9260         faceSetPtr[ iSide ]->erase( face[ iSide ]);
9261         // put face nodes to fnodes
9262         if ( face[ iSide ]->IsQuadratic() )
9263         {
9264           // use interlaced nodes iterator
9265           const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
9266           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9267           SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
9268           while ( nIter->more() )
9269             fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
9270         }
9271         else
9272         {
9273           fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
9274                                   face[ iSide ]->end_nodes() );
9275         }
9276         fnodes[ iSide ].push_back( fnodes[ iSide ].front());
9277       }
9278     }
9279
9280     // check similarity of elements of the sides
9281     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
9282       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9283       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9284         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9285       }
9286       else {
9287         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9288       }
9289       break; // do not return because it's necessary to remove tmp faces
9290     }
9291
9292     // set nodes to merge
9293     // -------------------
9294
9295     if ( face[0] && face[1] )  {
9296       const int nbNodes = face[0]->NbNodes();
9297       if ( nbNodes != face[1]->NbNodes() ) {
9298         MESSAGE("Diff nb of face nodes");
9299         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9300         break; // do not return because it s necessary to remove tmp faces
9301       }
9302       bool reverse[] = { false, false }; // order of nodes in the link
9303       for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9304         // analyse link orientation in faces
9305         int i1 = iLinkNode[ iSide ][ 0 ];
9306         int i2 = iLinkNode[ iSide ][ 1 ];
9307         reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9308       }
9309       int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
9310       int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
9311       for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
9312       {
9313         nReplaceMap.insert  ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
9314                                           fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
9315       }
9316
9317       // add other links of the faces to linkList
9318       // -----------------------------------------
9319
9320       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9321         linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
9322         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9323         if ( !iter_isnew.second ) { // already in a set: no need to process
9324           linkIdSet.erase( iter_isnew.first );
9325         }
9326         else // new in set == encountered for the first time: add
9327         {
9328           const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
9329           const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
9330           linkList[0].push_back ( NLink( n1, n2 ));
9331           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9332         }
9333       }
9334     } // 2 faces found
9335
9336     if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
9337       break;
9338
9339   } // loop on link lists
9340
9341   if ( aResult == SEW_OK &&
9342        ( //linkIt[0] != linkList[0].end() ||
9343          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9344     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9345              " " << (faceSetPtr[1]->empty()));
9346     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9347   }
9348
9349   // ====================================================================
9350   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9351   // ====================================================================
9352
9353   // delete temporary faces
9354 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9355 //  while ( tmpFaceIt->more() )
9356 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9357   list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9358   for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9359     aMesh->RemoveElement(*tmpFaceIt);
9360
9361   if ( aResult != SEW_OK)
9362     return aResult;
9363
9364   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9365   // loop on nodes replacement map
9366   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9367   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9368     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9369       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9370       nodeIDsToRemove.push_back( nToRemove->GetID() );
9371       // loop on elements sharing nToRemove
9372       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9373       while ( invElemIt->more() ) {
9374         const SMDS_MeshElement* e = invElemIt->next();
9375         // get a new suite of nodes: make replacement
9376         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9377         vector< const SMDS_MeshNode*> nodes( nbNodes );
9378         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9379         while ( nIt->more() ) {
9380           const SMDS_MeshNode* n =
9381             static_cast<const SMDS_MeshNode*>( nIt->next() );
9382           nnIt = nReplaceMap.find( n );
9383           if ( nnIt != nReplaceMap.end() ) {
9384             nbReplaced++;
9385             n = (*nnIt).second;
9386           }
9387           nodes[ i++ ] = n;
9388         }
9389         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9390         //         elemIDsToRemove.push_back( e->GetID() );
9391         //       else
9392         if ( nbReplaced )
9393           {
9394             SMDSAbs_ElementType etyp = e->GetType();
9395             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
9396             if (newElem)
9397               {
9398                 myLastCreatedElems.Append(newElem);
9399                 AddToSameGroups(newElem, e, aMesh);
9400                 int aShapeId = e->getshapeId();
9401                 if ( aShapeId )
9402                   {
9403                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
9404                   }
9405               }
9406             aMesh->RemoveElement(e);
9407           }
9408       }
9409     }
9410
9411   Remove( nodeIDsToRemove, true );
9412
9413   return aResult;
9414 }
9415
9416 //================================================================================
9417 /*!
9418  * \brief Find corresponding nodes in two sets of faces
9419  * \param theSide1 - first face set
9420  * \param theSide2 - second first face
9421  * \param theFirstNode1 - a boundary node of set 1
9422  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9423  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9424  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9425  * \param nReplaceMap - output map of corresponding nodes
9426  * \return bool  - is a success or not
9427  */
9428 //================================================================================
9429
9430 #ifdef _DEBUG_
9431 //#define DEBUG_MATCHING_NODES
9432 #endif
9433
9434 SMESH_MeshEditor::Sew_Error
9435 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9436                                     set<const SMDS_MeshElement*>& theSide2,
9437                                     const SMDS_MeshNode*          theFirstNode1,
9438                                     const SMDS_MeshNode*          theFirstNode2,
9439                                     const SMDS_MeshNode*          theSecondNode1,
9440                                     const SMDS_MeshNode*          theSecondNode2,
9441                                     TNodeNodeMap &                nReplaceMap)
9442 {
9443   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9444
9445   nReplaceMap.clear();
9446   if ( theFirstNode1 != theFirstNode2 )
9447     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9448   if ( theSecondNode1 != theSecondNode2 )
9449     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9450
9451   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9452   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9453
9454   list< NLink > linkList[2];
9455   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9456   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9457
9458   // loop on links in linkList; find faces by links and append links
9459   // of the found faces to linkList
9460   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9461   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9462     NLink link[] = { *linkIt[0], *linkIt[1] };
9463     if ( linkSet.find( link[0] ) == linkSet.end() )
9464       continue;
9465
9466     // by links, find faces in the face sets,
9467     // and find indices of link nodes in the found faces;
9468     // in a face set, there is only one or no face sharing a link
9469     // ---------------------------------------------------------------
9470
9471     const SMDS_MeshElement* face[] = { 0, 0 };
9472     list<const SMDS_MeshNode*> notLinkNodes[2];
9473     //bool reverse[] = { false, false }; // order of notLinkNodes
9474     int nbNodes[2];
9475     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9476     {
9477       const SMDS_MeshNode* n1 = link[iSide].first;
9478       const SMDS_MeshNode* n2 = link[iSide].second;
9479       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9480       set< const SMDS_MeshElement* > facesOfNode1;
9481       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9482       {
9483         // during a loop of the first node, we find all faces around n1,
9484         // during a loop of the second node, we find one face sharing both n1 and n2
9485         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9486         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9487         while ( fIt->more() ) { // loop on faces sharing a node
9488           const SMDS_MeshElement* f = fIt->next();
9489           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9490               ! facesOfNode1.insert( f ).second ) // f encounters twice
9491           {
9492             if ( face[ iSide ] ) {
9493               MESSAGE( "2 faces per link " );
9494               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9495             }
9496             face[ iSide ] = f;
9497             faceSet->erase( f );
9498
9499             // get not link nodes
9500             int nbN = f->NbNodes();
9501             if ( f->IsQuadratic() )
9502               nbN /= 2;
9503             nbNodes[ iSide ] = nbN;
9504             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9505             int i1 = f->GetNodeIndex( n1 );
9506             int i2 = f->GetNodeIndex( n2 );
9507             int iEnd = nbN, iBeg = -1, iDelta = 1;
9508             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9509             if ( reverse ) {
9510               std::swap( iEnd, iBeg ); iDelta = -1;
9511             }
9512             int i = i2;
9513             while ( true ) {
9514               i += iDelta;
9515               if ( i == iEnd ) i = iBeg + iDelta;
9516               if ( i == i1 ) break;
9517               nodes.push_back ( f->GetNode( i ) );
9518             }
9519           }
9520         }
9521       }
9522     }
9523     // check similarity of elements of the sides
9524     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9525       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9526       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9527         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9528       }
9529       else {
9530         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9531       }
9532     }
9533
9534     // set nodes to merge
9535     // -------------------
9536
9537     if ( face[0] && face[1] )  {
9538       if ( nbNodes[0] != nbNodes[1] ) {
9539         MESSAGE("Diff nb of face nodes");
9540         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9541       }
9542 #ifdef DEBUG_MATCHING_NODES
9543       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9544                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9545                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9546 #endif
9547       int nbN = nbNodes[0];
9548       {
9549         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9550         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9551         for ( int i = 0 ; i < nbN - 2; ++i ) {
9552 #ifdef DEBUG_MATCHING_NODES
9553           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9554 #endif
9555           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9556         }
9557       }
9558
9559       // add other links of the face 1 to linkList
9560       // -----------------------------------------
9561
9562       const SMDS_MeshElement* f0 = face[0];
9563       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9564       for ( int i = 0; i < nbN; i++ )
9565       {
9566         const SMDS_MeshNode* n2 = f0->GetNode( i );
9567         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9568           linkSet.insert( SMESH_TLink( n1, n2 ));
9569         if ( !iter_isnew.second ) { // already in a set: no need to process
9570           linkSet.erase( iter_isnew.first );
9571         }
9572         else // new in set == encountered for the first time: add
9573         {
9574 #ifdef DEBUG_MATCHING_NODES
9575           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9576                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9577 #endif
9578           linkList[0].push_back ( NLink( n1, n2 ));
9579           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9580         }
9581         n1 = n2;
9582       }
9583     } // 2 faces found
9584   } // loop on link lists
9585
9586   return SEW_OK;
9587 }
9588
9589 //================================================================================
9590 /*!
9591   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9592   \param theElems - the list of elements (edges or faces) to be replicated
9593   The nodes for duplication could be found from these elements
9594   \param theNodesNot - list of nodes to NOT replicate
9595   \param theAffectedElems - the list of elements (cells and edges) to which the
9596   replicated nodes should be associated to.
9597   \return TRUE if operation has been completed successfully, FALSE otherwise
9598 */
9599 //================================================================================
9600
9601 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9602                                     const TIDSortedElemSet& theNodesNot,
9603                                     const TIDSortedElemSet& theAffectedElems )
9604 {
9605   myLastCreatedElems.Clear();
9606   myLastCreatedNodes.Clear();
9607
9608   if ( theElems.size() == 0 )
9609     return false;
9610
9611   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9612   if ( !aMeshDS )
9613     return false;
9614
9615   bool res = false;
9616   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9617   // duplicate elements and nodes
9618   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9619   // replce nodes by duplications
9620   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9621   return res;
9622 }
9623
9624 //================================================================================
9625 /*!
9626   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9627   \param theMeshDS - mesh instance
9628   \param theElems - the elements replicated or modified (nodes should be changed)
9629   \param theNodesNot - nodes to NOT replicate
9630   \param theNodeNodeMap - relation of old node to new created node
9631   \param theIsDoubleElem - flag os to replicate element or modify
9632   \return TRUE if operation has been completed successfully, FALSE otherwise
9633 */
9634 //================================================================================
9635
9636 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
9637                                     const TIDSortedElemSet& theElems,
9638                                     const TIDSortedElemSet& theNodesNot,
9639                                     std::map< const SMDS_MeshNode*,
9640                                     const SMDS_MeshNode* >& theNodeNodeMap,
9641                                     const bool theIsDoubleElem )
9642 {
9643   MESSAGE("doubleNodes");
9644   // iterate on through element and duplicate them (by nodes duplication)
9645   bool res = false;
9646   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9647   for ( ;  elemItr != theElems.end(); ++elemItr )
9648   {
9649     const SMDS_MeshElement* anElem = *elemItr;
9650     if (!anElem)
9651       continue;
9652
9653     bool isDuplicate = false;
9654     // duplicate nodes to duplicate element
9655     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9656     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9657     int ind = 0;
9658     while ( anIter->more() )
9659     {
9660
9661       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9662       SMDS_MeshNode* aNewNode = aCurrNode;
9663       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9664         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9665       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9666       {
9667         // duplicate node
9668         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9669         theNodeNodeMap[ aCurrNode ] = aNewNode;
9670         myLastCreatedNodes.Append( aNewNode );
9671       }
9672       isDuplicate |= (aCurrNode != aNewNode);
9673       newNodes[ ind++ ] = aNewNode;
9674     }
9675     if ( !isDuplicate )
9676       continue;
9677
9678     if ( theIsDoubleElem )
9679       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
9680     else
9681       {
9682       MESSAGE("ChangeElementNodes");
9683       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9684       }
9685     res = true;
9686   }
9687   return res;
9688 }
9689
9690 //================================================================================
9691 /*!
9692   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9693   \param theNodes - identifiers of nodes to be doubled
9694   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
9695          nodes. If list of element identifiers is empty then nodes are doubled but
9696          they not assigned to elements
9697   \return TRUE if operation has been completed successfully, FALSE otherwise
9698 */
9699 //================================================================================
9700
9701 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
9702                                     const std::list< int >& theListOfModifiedElems )
9703 {
9704   MESSAGE("DoubleNodes");
9705   myLastCreatedElems.Clear();
9706   myLastCreatedNodes.Clear();
9707
9708   if ( theListOfNodes.size() == 0 )
9709     return false;
9710
9711   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9712   if ( !aMeshDS )
9713     return false;
9714
9715   // iterate through nodes and duplicate them
9716
9717   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9718
9719   std::list< int >::const_iterator aNodeIter;
9720   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9721   {
9722     int aCurr = *aNodeIter;
9723     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9724     if ( !aNode )
9725       continue;
9726
9727     // duplicate node
9728
9729     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9730     if ( aNewNode )
9731     {
9732       anOldNodeToNewNode[ aNode ] = aNewNode;
9733       myLastCreatedNodes.Append( aNewNode );
9734     }
9735   }
9736
9737   // Create map of new nodes for modified elements
9738
9739   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9740
9741   std::list< int >::const_iterator anElemIter;
9742   for ( anElemIter = theListOfModifiedElems.begin();
9743         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9744   {
9745     int aCurr = *anElemIter;
9746     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9747     if ( !anElem )
9748       continue;
9749
9750     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9751
9752     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9753     int ind = 0;
9754     while ( anIter->more() )
9755     {
9756       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9757       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9758       {
9759         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9760         aNodeArr[ ind++ ] = aNewNode;
9761       }
9762       else
9763         aNodeArr[ ind++ ] = aCurrNode;
9764     }
9765     anElemToNodes[ anElem ] = aNodeArr;
9766   }
9767
9768   // Change nodes of elements
9769
9770   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9771     anElemToNodesIter = anElemToNodes.begin();
9772   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9773   {
9774     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9775     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9776     if ( anElem )
9777       {
9778       MESSAGE("ChangeElementNodes");
9779       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9780       }
9781   }
9782
9783   return true;
9784 }
9785
9786 namespace {
9787
9788   //================================================================================
9789   /*!
9790   \brief Check if element located inside shape
9791   \return TRUE if IN or ON shape, FALSE otherwise
9792   */
9793   //================================================================================
9794
9795   template<class Classifier>
9796   bool isInside(const SMDS_MeshElement* theElem,
9797                 Classifier&             theClassifier,
9798                 const double            theTol)
9799   {
9800     gp_XYZ centerXYZ (0, 0, 0);
9801     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9802     while (aNodeItr->more())
9803       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
9804
9805     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9806     theClassifier.Perform(aPnt, theTol);
9807     TopAbs_State aState = theClassifier.State();
9808     return (aState == TopAbs_IN || aState == TopAbs_ON );
9809   }
9810
9811   //================================================================================
9812   /*!
9813    * \brief Classifier of the 3D point on the TopoDS_Face
9814    *        with interaface suitable for isInside()
9815    */
9816   //================================================================================
9817
9818   struct _FaceClassifier
9819   {
9820     Extrema_ExtPS       _extremum;
9821     BRepAdaptor_Surface _surface;
9822     TopAbs_State        _state;
9823
9824     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9825     {
9826       _extremum.Initialize( _surface,
9827                             _surface.FirstUParameter(), _surface.LastUParameter(),
9828                             _surface.FirstVParameter(), _surface.LastVParameter(),
9829                             _surface.Tolerance(), _surface.Tolerance() );
9830     }
9831     void Perform(const gp_Pnt& aPnt, double theTol)
9832     {
9833       _state = TopAbs_OUT;
9834       _extremum.Perform(aPnt);
9835       if ( _extremum.IsDone() )
9836         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9837 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
9838           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9839 #else
9840           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9841 #endif
9842     }
9843     TopAbs_State State() const
9844     {
9845       return _state;
9846     }
9847   };
9848 }
9849
9850 //================================================================================
9851 /*!
9852   \brief Identify the elements that will be affected by node duplication (actual duplication is not performed.
9853   This method is the first step of DoubleNodeElemGroupsInRegion.
9854   \param theElems - list of groups of elements (edges or faces) to be replicated
9855   \param theNodesNot - list of groups of nodes not to replicated
9856   \param theShape - shape to detect affected elements (element which geometric center
9857          located on or inside shape).
9858          The replicated nodes should be associated to affected elements.
9859   \return groups of affected elements
9860   \sa DoubleNodeElemGroupsInRegion()
9861  */
9862 //================================================================================
9863
9864 bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
9865                                                    const TIDSortedElemSet& theNodesNot,
9866                                                    const TopoDS_Shape&     theShape,
9867                                                    TIDSortedElemSet&       theAffectedElems)
9868 {
9869   if ( theShape.IsNull() )
9870     return false;
9871
9872   const double aTol = Precision::Confusion();
9873   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
9874   auto_ptr<_FaceClassifier>              aFaceClassifier;
9875   if ( theShape.ShapeType() == TopAbs_SOLID )
9876   {
9877     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
9878     bsc3d->PerformInfinitePoint(aTol);
9879   }
9880   else if (theShape.ShapeType() == TopAbs_FACE )
9881   {
9882     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
9883   }
9884
9885   // iterates on indicated elements and get elements by back references from their nodes
9886   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9887   for ( ;  elemItr != theElems.end(); ++elemItr )
9888   {
9889     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
9890     if (!anElem)
9891       continue;
9892
9893     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
9894     while ( nodeItr->more() )
9895     {
9896       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
9897       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
9898         continue;
9899       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
9900       while ( backElemItr->more() )
9901       {
9902         const SMDS_MeshElement* curElem = backElemItr->next();
9903         if ( curElem && theElems.find(curElem) == theElems.end() &&
9904              ( bsc3d.get() ?
9905                isInside( curElem, *bsc3d, aTol ) :
9906                isInside( curElem, *aFaceClassifier, aTol )))
9907           theAffectedElems.insert( curElem );
9908       }
9909     }
9910   }
9911   return true;
9912 }
9913
9914 //================================================================================
9915 /*!
9916   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9917   \param theElems - group of of elements (edges or faces) to be replicated
9918   \param theNodesNot - group of nodes not to replicate
9919   \param theShape - shape to detect affected elements (element which geometric center
9920   located on or inside shape).
9921   The replicated nodes should be associated to affected elements.
9922   \return TRUE if operation has been completed successfully, FALSE otherwise
9923 */
9924 //================================================================================
9925
9926 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
9927                                             const TIDSortedElemSet& theNodesNot,
9928                                             const TopoDS_Shape&     theShape )
9929 {
9930   if ( theShape.IsNull() )
9931     return false;
9932
9933   const double aTol = Precision::Confusion();
9934   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
9935   auto_ptr<_FaceClassifier>              aFaceClassifier;
9936   if ( theShape.ShapeType() == TopAbs_SOLID )
9937   {
9938     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
9939     bsc3d->PerformInfinitePoint(aTol);
9940   }
9941   else if (theShape.ShapeType() == TopAbs_FACE )
9942   {
9943     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
9944   }
9945
9946   // iterates on indicated elements and get elements by back references from their nodes
9947   TIDSortedElemSet anAffected;
9948   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9949   for ( ;  elemItr != theElems.end(); ++elemItr )
9950   {
9951     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
9952     if (!anElem)
9953       continue;
9954
9955     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
9956     while ( nodeItr->more() )
9957     {
9958       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
9959       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
9960         continue;
9961       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
9962       while ( backElemItr->more() )
9963       {
9964         const SMDS_MeshElement* curElem = backElemItr->next();
9965         if ( curElem && theElems.find(curElem) == theElems.end() &&
9966              ( bsc3d.get() ?
9967                isInside( curElem, *bsc3d, aTol ) :
9968                isInside( curElem, *aFaceClassifier, aTol )))
9969           anAffected.insert( curElem );
9970       }
9971     }
9972   }
9973   return DoubleNodes( theElems, theNodesNot, anAffected );
9974 }
9975
9976 /*!
9977  *  \brief compute an oriented angle between two planes defined by four points.
9978  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
9979  *  @param p0 base of the rotation axe
9980  *  @param p1 extremity of the rotation axe
9981  *  @param g1 belongs to the first plane
9982  *  @param g2 belongs to the second plane
9983  */
9984 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
9985 {
9986 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
9987 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
9988 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
9989 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
9990   gp_Vec vref(p0, p1);
9991   gp_Vec v1(p0, g1);
9992   gp_Vec v2(p0, g2);
9993   gp_Vec n1 = vref.Crossed(v1);
9994   gp_Vec n2 = vref.Crossed(v2);
9995   return n2.AngleWithRef(n1, vref);
9996 }
9997
9998 /*!
9999  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10000  *  The list of groups must contain at least two groups. The groups have to be disjoint: no common element into two different groups.
10001  * The nodes of the internal faces at the boundaries of the groups are doubled. Optionally, the internal faces are replaced by flat elements.
10002  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
10003  * The flat elements are stored in groups of volumes. These groups are named according to the position of the group in the list:
10004  * 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.
10005  * 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.
10006  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
10007  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
10008  * @param theElems - list of groups of volumes, where a group of volume is a set of
10009  * SMDS_MeshElements sorted by Id.
10010  * @param createJointElems - if TRUE, create the elements
10011  * @return TRUE if operation has been completed successfully, FALSE otherwise
10012  */
10013 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10014                                                      bool createJointElems)
10015 {
10016   MESSAGE("----------------------------------------------");
10017   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10018   MESSAGE("----------------------------------------------");
10019
10020   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10021   meshDS->BuildDownWardConnectivity(true);
10022   CHRONO(50);
10023   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10024
10025   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10026   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10027   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10028
10029   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10030   std::map<int,int>celldom; // cell vtkId --> domain
10031   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10032   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10033   faceDomains.clear();
10034   celldom.clear();
10035   cellDomains.clear();
10036   nodeDomains.clear();
10037   std::map<int,int> emptyMap;
10038   std::set<int> emptySet;
10039   emptyMap.clear();
10040
10041   MESSAGE(".. Number of domains :"<<theElems.size());
10042
10043   // Check if the domains do not share an element
10044   for (int idom = 0; idom < theElems.size()-1; idom++)
10045     {
10046 //       MESSAGE("... Check of domain #" << idom);
10047       const TIDSortedElemSet& domain = theElems[idom];
10048       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10049       for (; elemItr != domain.end(); ++elemItr)
10050         {
10051           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10052           int idombisdeb = idom + 1 ;
10053           for (int idombis = idombisdeb; idombis < theElems.size(); idombis++) // check if the element belongs to a domain further in the list
10054           {
10055             const TIDSortedElemSet& domainbis = theElems[idombis];
10056             if ( domainbis.count(anElem) )
10057             {
10058               MESSAGE(".... Domain #" << idom);
10059               MESSAGE(".... Domain #" << idombis);
10060               throw SALOME_Exception("The domains are not disjoint.");
10061               return false ;
10062             }
10063           }
10064         }
10065     }
10066
10067   for (int idom = 0; idom < theElems.size(); idom++)
10068     {
10069
10070       // --- build a map (face to duplicate --> volume to modify)
10071       //     with all the faces shared by 2 domains (group of elements)
10072       //     and corresponding volume of this domain, for each shared face.
10073       //     a volume has a face shared by 2 domains if it has a neighbor which is not in his domain.
10074
10075       MESSAGE("... Neighbors of domain #" << idom);
10076       const TIDSortedElemSet& domain = theElems[idom];
10077       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10078       for (; elemItr != domain.end(); ++elemItr)
10079         {
10080           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10081           if (!anElem)
10082             continue;
10083           int vtkId = anElem->getVtkId();
10084           //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
10085           int neighborsVtkIds[NBMAXNEIGHBORS];
10086           int downIds[NBMAXNEIGHBORS];
10087           unsigned char downTypes[NBMAXNEIGHBORS];
10088           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10089           for (int n = 0; n < nbNeighbors; n++)
10090             {
10091               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10092               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10093               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10094                 {
10095                   bool ok = false ;
10096                   for (int idombis = 0; idombis < theElems.size(); idombis++) // check if the neighbor belongs to another domain of the list
10097                   {
10098                     // MESSAGE("Domain " << idombis);
10099                     const TIDSortedElemSet& domainbis = theElems[idombis];
10100                     if ( domainbis.count(elem)) ok = true ; // neighbor is in a correct domain : face is kept
10101                   }
10102                   if ( ok ) // the characteristics of the face is stored
10103                   {
10104                     DownIdType face(downIds[n], downTypes[n]);
10105                     if (!faceDomains.count(face))
10106                       faceDomains[face] = emptyMap; // create an empty entry for face
10107                     if (!faceDomains[face].count(idom))
10108                       {
10109                         faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10110                         celldom[vtkId] = idom;
10111                         //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
10112                       }
10113                   }
10114                 }
10115             }
10116         }
10117     }
10118
10119   //MESSAGE("Number of shared faces " << faceDomains.size());
10120   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10121
10122   // --- explore the shared faces domain by domain,
10123   //     explore the nodes of the face and see if they belong to a cell in the domain,
10124   //     which has only a node or an edge on the border (not a shared face)
10125
10126   for (int idomain = 0; idomain < theElems.size(); idomain++)
10127     {
10128       //MESSAGE("Domain " << idomain);
10129       const TIDSortedElemSet& domain = theElems[idomain];
10130       itface = faceDomains.begin();
10131       for (; itface != faceDomains.end(); ++itface)
10132         {
10133           std::map<int, int> domvol = itface->second;
10134           if (!domvol.count(idomain))
10135             continue;
10136           DownIdType face = itface->first;
10137           //MESSAGE(" --- face " << face.cellId);
10138           std::set<int> oldNodes;
10139           oldNodes.clear();
10140           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10141           std::set<int>::iterator itn = oldNodes.begin();
10142           for (; itn != oldNodes.end(); ++itn)
10143             {
10144               int oldId = *itn;
10145               //MESSAGE("     node " << oldId);
10146               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10147               for (int i=0; i<l.ncells; i++)
10148                 {
10149                   int vtkId = l.cells[i];
10150                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10151                   if (!domain.count(anElem))
10152                     continue;
10153                   int vtkType = grid->GetCellType(vtkId);
10154                   int downId = grid->CellIdToDownId(vtkId);
10155                   if (downId < 0)
10156                     {
10157                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
10158                       continue; // not OK at this stage of the algorithm:
10159                                 //no cells created after BuildDownWardConnectivity
10160                     }
10161                   DownIdType aCell(downId, vtkType);
10162                   if (!cellDomains.count(aCell))
10163                     cellDomains[aCell] = emptyMap; // create an empty entry for cell
10164                   cellDomains[aCell][idomain] = vtkId;
10165                   celldom[vtkId] = idomain;
10166                   //MESSAGE("       cell " << vtkId << " domain " << idomain);
10167                 }
10168             }
10169         }
10170     }
10171
10172   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10173   //     for each shared face, get the nodes
10174   //     for each node, for each domain of the face, create a clone of the node
10175
10176   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10177   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10178   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
10179
10180   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10181   std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
10182   std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
10183
10184   MESSAGE(".. Duplication of the nodes");
10185   for (int idomain = 0; idomain < theElems.size(); idomain++)
10186     {
10187       itface = faceDomains.begin();
10188       for (; itface != faceDomains.end(); ++itface)
10189         {
10190           std::map<int, int> domvol = itface->second;
10191           if (!domvol.count(idomain))
10192             continue;
10193           DownIdType face = itface->first;
10194           //MESSAGE(" --- face " << face.cellId);
10195           std::set<int> oldNodes;
10196           oldNodes.clear();
10197           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10198           std::set<int>::iterator itn = oldNodes.begin();
10199           for (; itn != oldNodes.end(); ++itn)
10200             {
10201               int oldId = *itn;
10202               //MESSAGE("-+-+-a node " << oldId);
10203               if (!nodeDomains.count(oldId))
10204                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10205               if (nodeDomains[oldId].empty())
10206                 {
10207                   nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
10208                   //MESSAGE("-+-+-b     oldNode " << oldId << " domain " << idomain);
10209                 }
10210               std::map<int, int>::iterator itdom = domvol.begin();
10211               for (; itdom != domvol.end(); ++itdom)
10212                 {
10213                   int idom = itdom->first;
10214                   //MESSAGE("         domain " << idom);
10215                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
10216                     {
10217                       if (nodeDomains[oldId].size() >= 2) // a multiple node
10218                         {
10219                           vector<int> orderedDoms;
10220                           //MESSAGE("multiple node " << oldId);
10221                           if (mutipleNodes.count(oldId))
10222                             orderedDoms = mutipleNodes[oldId];
10223                           else
10224                             {
10225                               map<int,int>::iterator it = nodeDomains[oldId].begin();
10226                               for (; it != nodeDomains[oldId].end(); ++it)
10227                                 orderedDoms.push_back(it->first);
10228                             }
10229                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
10230                           //stringstream txt;
10231                           //for (int i=0; i<orderedDoms.size(); i++)
10232                           //  txt << orderedDoms[i] << " ";
10233                           //MESSAGE("orderedDoms " << txt.str());
10234                           mutipleNodes[oldId] = orderedDoms;
10235                         }
10236                       double *coords = grid->GetPoint(oldId);
10237                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10238                       int newId = newNode->getVtkId();
10239                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
10240                       //MESSAGE("-+-+-c     oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
10241                     }
10242                 }
10243             }
10244         }
10245     }
10246
10247   MESSAGE(".. Creation of elements");
10248   for (int idomain = 0; idomain < theElems.size(); idomain++)
10249     {
10250       itface = faceDomains.begin();
10251       for (; itface != faceDomains.end(); ++itface)
10252         {
10253           std::map<int, int> domvol = itface->second;
10254           if (!domvol.count(idomain))
10255             continue;
10256           DownIdType face = itface->first;
10257           //MESSAGE(" --- face " << face.cellId);
10258           std::set<int> oldNodes;
10259           oldNodes.clear();
10260           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10261           int nbMultipleNodes = 0;
10262           std::set<int>::iterator itn = oldNodes.begin();
10263           for (; itn != oldNodes.end(); ++itn)
10264             {
10265               int oldId = *itn;
10266               if (mutipleNodes.count(oldId))
10267                 nbMultipleNodes++;
10268             }
10269           if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains
10270             {
10271               //MESSAGE("multiple Nodes detected on a shared face");
10272               int downId = itface->first.cellId;
10273               unsigned char cellType = itface->first.cellType;
10274               // --- shared edge or shared face ?
10275               if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
10276                 {
10277                   int nodes[3];
10278                   int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
10279                   for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
10280                     if (mutipleNodes.count(nodes[i]))
10281                       if (!mutipleNodesToFace.count(nodes[i]))
10282                         mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
10283                 }
10284               else // shared face (between two volumes)
10285                 {
10286                   int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
10287                   const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
10288                   const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
10289                   for (int ie =0; ie < nbEdges; ie++)
10290                     {
10291                       int nodes[3];
10292                       int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
10293                       if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
10294                         {
10295                           vector<int> vn0 = mutipleNodes[nodes[0]];
10296                           vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
10297                           vector<int> doms;
10298                           for (int i0 = 0; i0 < vn0.size(); i0++)
10299                             for (int i1 = 0; i1 < vn1.size(); i1++)
10300                               if (vn0[i0] == vn1[i1])
10301                                 doms.push_back(vn0[i0]);
10302                           if (doms.size() >2)
10303                             {
10304                               //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
10305                               double *coords = grid->GetPoint(nodes[0]);
10306                               gp_Pnt p0(coords[0], coords[1], coords[2]);
10307                               coords = grid->GetPoint(nodes[nbNodes - 1]);
10308                               gp_Pnt p1(coords[0], coords[1], coords[2]);
10309                               gp_Pnt gref;
10310                               int vtkVolIds[1000];  // an edge can belong to a lot of volumes
10311                               map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
10312                               map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
10313                               int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
10314                               for (int id=0; id < doms.size(); id++)
10315                                 {
10316                                   int idom = doms[id];
10317                                   for (int ivol=0; ivol<nbvol; ivol++)
10318                                     {
10319                                       int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
10320                                       SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
10321                                       if (theElems[idom].count(elem))
10322                                         {
10323                                           SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
10324                                           domvol[idom] = svol;
10325                                           //MESSAGE("  domain " << idom << " volume " << elem->GetID());
10326                                           double values[3];
10327                                           vtkIdType npts = 0;
10328                                           vtkIdType* pts = 0;
10329                                           grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
10330                                           SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
10331                                           if (id ==0)
10332                                             {
10333                                               gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
10334                                               angleDom[idom] = 0;
10335                                             }
10336                                           else
10337                                             {
10338                                               gp_Pnt g(values[0], values[1], values[2]);
10339                                               angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
10340                                               //MESSAGE("  angle=" << angleDom[idom]);
10341                                             }
10342                                           break;
10343                                         }
10344                                     }
10345                                 }
10346                               map<double, int> sortedDom; // sort domains by angle
10347                               for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
10348                                 sortedDom[ia->second] = ia->first;
10349                               vector<int> vnodes;
10350                               vector<int> vdom;
10351                               for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
10352                                 {
10353                                   vdom.push_back(ib->second);
10354                                   //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
10355                                 }
10356                               for (int ino = 0; ino < nbNodes; ino++)
10357                                 vnodes.push_back(nodes[ino]);
10358                               edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
10359                             }
10360                         }
10361                     }
10362                 }
10363             }
10364         }
10365     }
10366
10367   // --- iterate on shared faces (volumes to modify, face to extrude)
10368   //     get node id's of the face (id SMDS = id VTK)
10369   //     create flat element with old and new nodes if requested
10370
10371   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
10372   //     (domain1 X domain2) = domain1 + MAXINT*domain2
10373
10374   std::map<int, std::map<long,int> > nodeQuadDomains;
10375   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10376
10377   MESSAGE(".. Creation of elements: simple junction");
10378   if (createJointElems)
10379     {
10380       int idg;
10381       string joints2DName = "joints2D";
10382       mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg);
10383       SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
10384       string joints3DName = "joints3D";
10385       mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg);
10386       SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
10387
10388       itface = faceDomains.begin();
10389       for (; itface != faceDomains.end(); ++itface)
10390         {
10391           DownIdType face = itface->first;
10392           std::set<int> oldNodes;
10393           std::set<int>::iterator itn;
10394           oldNodes.clear();
10395           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10396
10397           std::map<int, int> domvol = itface->second;
10398           std::map<int, int>::iterator itdom = domvol.begin();
10399           int dom1 = itdom->first;
10400           int vtkVolId = itdom->second;
10401           itdom++;
10402           int dom2 = itdom->first;
10403           SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
10404                                                              nodeQuadDomains);
10405           stringstream grpname;
10406           grpname << "j_";
10407           if (dom1 < dom2)
10408             grpname << dom1 << "_" << dom2;
10409           else
10410             grpname << dom2 << "_" << dom1;
10411           string namegrp = grpname.str();
10412           if (!mapOfJunctionGroups.count(namegrp))
10413             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
10414           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10415           if (sgrp)
10416             sgrp->Add(vol->GetID());
10417           if (vol->GetType() == SMDSAbs_Volume)
10418             joints3DGrp->Add(vol->GetID());
10419           else if (vol->GetType() == SMDSAbs_Face)
10420             joints2DGrp->Add(vol->GetID());
10421         }
10422     }
10423
10424   // --- create volumes on multiple domain intersection if requested
10425   //     iterate on mutipleNodesToFace
10426   //     iterate on edgesMultiDomains
10427
10428   MESSAGE(".. Creation of elements: multiple junction");
10429   if (createJointElems)
10430     {
10431       // --- iterate on mutipleNodesToFace
10432
10433       std::map<int, std::vector<int> >::iterator itn =  mutipleNodesToFace.begin();
10434       for (; itn != mutipleNodesToFace.end(); ++itn)
10435         {
10436           int node = itn->first;
10437           vector<int> orderDom = itn->second;
10438           vector<vtkIdType> orderedNodes;
10439           for (int idom = 0; idom <orderDom.size(); idom++)
10440             orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
10441             SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
10442
10443             stringstream grpname;
10444             grpname << "m2j_";
10445             grpname << 0 << "_" << 0;
10446             int idg;
10447             string namegrp = grpname.str();
10448             if (!mapOfJunctionGroups.count(namegrp))
10449               mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
10450             SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10451             if (sgrp)
10452               sgrp->Add(face->GetID());
10453         }
10454
10455       // --- iterate on edgesMultiDomains
10456
10457       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
10458       for (; ite != edgesMultiDomains.end(); ++ite)
10459         {
10460           vector<int> nodes = ite->first;
10461           vector<int> orderDom = ite->second;
10462           vector<vtkIdType> orderedNodes;
10463           if (nodes.size() == 2)
10464             {
10465               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
10466               for (int ino=0; ino < nodes.size(); ino++)
10467                 if (orderDom.size() == 3)
10468                   for (int idom = 0; idom <orderDom.size(); idom++)
10469                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
10470                 else
10471                   for (int idom = orderDom.size()-1; idom >=0; idom--)
10472                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
10473               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
10474
10475               int idg;
10476               string namegrp = "jointsMultiples";
10477               if (!mapOfJunctionGroups.count(namegrp))
10478                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
10479               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10480               if (sgrp)
10481                 sgrp->Add(vol->GetID());
10482             }
10483           else
10484             {
10485               INFOS("Quadratic multiple joints not implemented");
10486               // TODO quadratic nodes
10487             }
10488         }
10489     }
10490
10491   // --- list the explicit faces and edges of the mesh that need to be modified,
10492   //     i.e. faces and edges built with one or more duplicated nodes.
10493   //     associate these faces or edges to their corresponding domain.
10494   //     only the first domain found is kept when a face or edge is shared
10495
10496   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
10497   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
10498   faceOrEdgeDom.clear();
10499   feDom.clear();
10500
10501   MESSAGE(".. Modification of elements");
10502   for (int idomain = 0; idomain < theElems.size(); idomain++)
10503     {
10504       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
10505       for (; itnod != nodeDomains.end(); ++itnod)
10506         {
10507           int oldId = itnod->first;
10508           //MESSAGE("     node " << oldId);
10509           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10510           for (int i = 0; i < l.ncells; i++)
10511             {
10512               int vtkId = l.cells[i];
10513               int vtkType = grid->GetCellType(vtkId);
10514               int downId = grid->CellIdToDownId(vtkId);
10515               if (downId < 0)
10516                 continue; // new cells: not to be modified
10517               DownIdType aCell(downId, vtkType);
10518               int volParents[1000];
10519               int nbvol = grid->GetParentVolumes(volParents, vtkId);
10520               for (int j = 0; j < nbvol; j++)
10521                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
10522                   if (!feDom.count(vtkId))
10523                     {
10524                       feDom[vtkId] = idomain;
10525                       faceOrEdgeDom[aCell] = emptyMap;
10526                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
10527                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
10528                       //        << " type " << vtkType << " downId " << downId);
10529                     }
10530             }
10531         }
10532     }
10533
10534   // --- iterate on shared faces (volumes to modify, face to extrude)
10535   //     get node id's of the face
10536   //     replace old nodes by new nodes in volumes, and update inverse connectivity
10537
10538   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
10539   for (int m=0; m<3; m++)
10540     {
10541       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
10542       itface = (*amap).begin();
10543       for (; itface != (*amap).end(); ++itface)
10544         {
10545           DownIdType face = itface->first;
10546           std::set<int> oldNodes;
10547           std::set<int>::iterator itn;
10548           oldNodes.clear();
10549           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10550           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
10551           std::map<int, int> localClonedNodeIds;
10552
10553           std::map<int, int> domvol = itface->second;
10554           std::map<int, int>::iterator itdom = domvol.begin();
10555           for (; itdom != domvol.end(); ++itdom)
10556             {
10557               int idom = itdom->first;
10558               int vtkVolId = itdom->second;
10559               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
10560               localClonedNodeIds.clear();
10561               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10562                 {
10563                   int oldId = *itn;
10564                   if (nodeDomains[oldId].count(idom))
10565                     {
10566                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10567                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
10568                     }
10569                 }
10570               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10571             }
10572         }
10573     }
10574
10575   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
10576   grid->BuildLinks();
10577
10578   CHRONOSTOP(50);
10579   counters::stats();
10580   return true;
10581 }
10582
10583 /*!
10584  * \brief Double nodes on some external faces and create flat elements.
10585  * Flat elements are mainly used by some types of mechanic calculations.
10586  *
10587  * Each group of the list must be constituted of faces.
10588  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10589  * @param theElems - list of groups of faces, where a group of faces is a set of
10590  * SMDS_MeshElements sorted by Id.
10591  * @return TRUE if operation has been completed successfully, FALSE otherwise
10592  */
10593 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
10594 {
10595   MESSAGE("-------------------------------------------------");
10596   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
10597   MESSAGE("-------------------------------------------------");
10598
10599   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10600
10601   // --- For each group of faces
10602   //     duplicate the nodes, create a flat element based on the face
10603   //     replace the nodes of the faces by their clones
10604
10605   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
10606   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
10607   clonedNodes.clear();
10608   intermediateNodes.clear();
10609   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10610   mapOfJunctionGroups.clear();
10611
10612   for (int idom = 0; idom < theElems.size(); idom++)
10613     {
10614       const TIDSortedElemSet& domain = theElems[idom];
10615       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10616       for (; elemItr != domain.end(); ++elemItr)
10617         {
10618           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10619           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
10620           if (!aFace)
10621             continue;
10622           // MESSAGE("aFace=" << aFace->GetID());
10623           bool isQuad = aFace->IsQuadratic();
10624           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
10625
10626           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
10627
10628           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
10629           while (nodeIt->more())
10630             {
10631               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
10632               bool isMedium = isQuad && (aFace->IsMediumNode(node));
10633               if (isMedium)
10634                 ln2.push_back(node);
10635               else
10636                 ln0.push_back(node);
10637
10638               const SMDS_MeshNode* clone = 0;
10639               if (!clonedNodes.count(node))
10640                 {
10641                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
10642                   clonedNodes[node] = clone;
10643                 }
10644               else
10645                 clone = clonedNodes[node];
10646
10647               if (isMedium)
10648                 ln3.push_back(clone);
10649               else
10650                 ln1.push_back(clone);
10651
10652               const SMDS_MeshNode* inter = 0;
10653               if (isQuad && (!isMedium))
10654                 {
10655                   if (!intermediateNodes.count(node))
10656                     {
10657                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
10658                       intermediateNodes[node] = inter;
10659                     }
10660                   else
10661                     inter = intermediateNodes[node];
10662                   ln4.push_back(inter);
10663                 }
10664             }
10665
10666           // --- extrude the face
10667
10668           vector<const SMDS_MeshNode*> ln;
10669           SMDS_MeshVolume* vol = 0;
10670           vtkIdType aType = aFace->GetVtkType();
10671           switch (aType)
10672           {
10673             case VTK_TRIANGLE:
10674               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
10675               // MESSAGE("vol prism " << vol->GetID());
10676               ln.push_back(ln1[0]);
10677               ln.push_back(ln1[1]);
10678               ln.push_back(ln1[2]);
10679               break;
10680             case VTK_QUAD:
10681               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
10682               // MESSAGE("vol hexa " << vol->GetID());
10683               ln.push_back(ln1[0]);
10684               ln.push_back(ln1[1]);
10685               ln.push_back(ln1[2]);
10686               ln.push_back(ln1[3]);
10687               break;
10688             case VTK_QUADRATIC_TRIANGLE:
10689               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
10690                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
10691               // MESSAGE("vol quad prism " << vol->GetID());
10692               ln.push_back(ln1[0]);
10693               ln.push_back(ln1[1]);
10694               ln.push_back(ln1[2]);
10695               ln.push_back(ln3[0]);
10696               ln.push_back(ln3[1]);
10697               ln.push_back(ln3[2]);
10698               break;
10699             case VTK_QUADRATIC_QUAD:
10700 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
10701 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
10702 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
10703               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
10704                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
10705                                       ln4[0], ln4[1], ln4[2], ln4[3]);
10706               // MESSAGE("vol quad hexa " << vol->GetID());
10707               ln.push_back(ln1[0]);
10708               ln.push_back(ln1[1]);
10709               ln.push_back(ln1[2]);
10710               ln.push_back(ln1[3]);
10711               ln.push_back(ln3[0]);
10712               ln.push_back(ln3[1]);
10713               ln.push_back(ln3[2]);
10714               ln.push_back(ln3[3]);
10715               break;
10716             case VTK_POLYGON:
10717               break;
10718             default:
10719               break;
10720           }
10721
10722           if (vol)
10723             {
10724               stringstream grpname;
10725               grpname << "jf_";
10726               grpname << idom;
10727               int idg;
10728               string namegrp = grpname.str();
10729               if (!mapOfJunctionGroups.count(namegrp))
10730                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
10731               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10732               if (sgrp)
10733                 sgrp->Add(vol->GetID());
10734             }
10735
10736           // --- modify the face
10737
10738           aFace->ChangeNodes(&ln[0], ln.size());
10739         }
10740     }
10741   return true;
10742 }
10743
10744 /*!
10745  *  \brief identify all the elements around a geom shape, get the faces delimiting the hole
10746  *  Build groups of volume to remove, groups of faces to replace on the skin of the object,
10747  *  groups of faces to remove inside the object, (idem edges).
10748  *  Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape)
10749  */
10750 void SMESH_MeshEditor::CreateHoleSkin(double radius,
10751                                       const TopoDS_Shape& theShape,
10752                                       SMESH_NodeSearcher* theNodeSearcher,
10753                                       const char* groupName,
10754                                       std::vector<double>&   nodesCoords,
10755                                       std::vector<std::vector<int> >& listOfListOfNodes)
10756 {
10757   MESSAGE("--------------------------------");
10758   MESSAGE("SMESH_MeshEditor::CreateHoleSkin");
10759   MESSAGE("--------------------------------");
10760
10761   // --- zone of volumes to remove is given :
10762   //     1 either by a geom shape (one or more vertices) and a radius,
10763   //     2 either by a group of nodes (representative of the shape)to use with the radius,
10764   //     3 either by a group of nodes where all the elements build on one of this nodes are to remove,
10765   //     In the case 2, the group of nodes is an external group of nodes from another mesh,
10766   //     In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter),
10767   //     defined by it's name.
10768
10769   SMESHDS_GroupBase* groupDS = 0;
10770   SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups();
10771   while ( groupIt->more() )
10772     {
10773       groupDS = 0;
10774       SMESH_Group * group = groupIt->next();
10775       if ( !group ) continue;
10776       groupDS = group->GetGroupDS();
10777       if ( !groupDS || groupDS->IsEmpty() ) continue;
10778       std::string grpName = group->GetName();
10779       //MESSAGE("grpName=" << grpName);
10780       if (grpName == groupName)
10781         break;
10782       else
10783         groupDS = 0;
10784     }
10785
10786   bool isNodeGroup = false;
10787   bool isNodeCoords = false;
10788   if (groupDS)
10789     {
10790       if (groupDS->GetType() != SMDSAbs_Node)
10791         return;
10792       isNodeGroup = true;     // a group of nodes exists and it is in this mesh
10793     }
10794
10795   if (nodesCoords.size() > 0)
10796     isNodeCoords = true; // a list o nodes given by their coordinates
10797   //MESSAGE("---" << isNodeGroup << " " << isNodeCoords);
10798
10799   // --- define groups to build
10800
10801   int idg; // --- group of SMDS volumes
10802   string grpvName = groupName;
10803   grpvName += "_vol";
10804   SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
10805   if (!grp)
10806     {
10807       MESSAGE("group not created " << grpvName);
10808       return;
10809     }
10810   SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
10811
10812   int idgs; // --- group of SMDS faces on the skin
10813   string grpsName = groupName;
10814   grpsName += "_skin";
10815   SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
10816   if (!grps)
10817     {
10818       MESSAGE("group not created " << grpsName);
10819       return;
10820     }
10821   SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
10822
10823   int idgi; // --- group of SMDS faces internal (several shapes)
10824   string grpiName = groupName;
10825   grpiName += "_internalFaces";
10826   SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
10827   if (!grpi)
10828     {
10829       MESSAGE("group not created " << grpiName);
10830       return;
10831     }
10832   SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
10833
10834   int idgei; // --- group of SMDS faces internal (several shapes)
10835   string grpeiName = groupName;
10836   grpeiName += "_internalEdges";
10837   SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
10838   if (!grpei)
10839     {
10840       MESSAGE("group not created " << grpeiName);
10841       return;
10842     }
10843   SMESHDS_Group *sgrpei = dynamic_cast<SMESHDS_Group*>(grpei->GetGroupDS());
10844
10845   // --- build downward connectivity
10846
10847   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10848   meshDS->BuildDownWardConnectivity(true);
10849   SMDS_UnstructuredGrid* grid = meshDS->getGrid();
10850
10851   // --- set of volumes detected inside
10852
10853   std::set<int> setOfInsideVol;
10854   std::set<int> setOfVolToCheck;
10855
10856   std::vector<gp_Pnt> gpnts;
10857   gpnts.clear();
10858
10859   if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
10860     {
10861       MESSAGE("group of nodes provided");
10862       SMDS_ElemIteratorPtr elemIt = groupDS->GetElements();
10863       while ( elemIt->more() )
10864         {
10865           const SMDS_MeshElement* elem = elemIt->next();
10866           if (!elem)
10867             continue;
10868           const SMDS_MeshNode* node = dynamic_cast<const SMDS_MeshNode*>(elem);
10869           if (!node)
10870             continue;
10871           SMDS_MeshElement* vol = 0;
10872           SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume);
10873           while (volItr->more())
10874             {
10875               vol = (SMDS_MeshElement*)volItr->next();
10876               setOfInsideVol.insert(vol->getVtkId());
10877               sgrp->Add(vol->GetID());
10878             }
10879         }
10880     }
10881   else if (isNodeCoords)
10882     {
10883       MESSAGE("list of nodes coordinates provided");
10884       int i = 0;
10885       int k = 0;
10886       while (i < nodesCoords.size()-2)
10887         {
10888           double x = nodesCoords[i++];
10889           double y = nodesCoords[i++];
10890           double z = nodesCoords[i++];
10891           gp_Pnt p = gp_Pnt(x, y ,z);
10892           gpnts.push_back(p);
10893           MESSAGE("TopoDS_Vertex " << k++ << " " << p.X() << " " << p.Y() << " " << p.Z());
10894         }
10895     }
10896   else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius
10897     {
10898       MESSAGE("no group of nodes provided, using vertices from geom shape, and radius");
10899       TopTools_IndexedMapOfShape vertexMap;
10900       TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap );
10901       gp_Pnt p = gp_Pnt(0,0,0);
10902       if (vertexMap.Extent() < 1)
10903         return;
10904
10905       for ( int i = 1; i <= vertexMap.Extent(); ++i )
10906         {
10907           const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i ));
10908           p = BRep_Tool::Pnt(vertex);
10909           gpnts.push_back(p);
10910           MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z());
10911         }
10912     }
10913
10914   if (gpnts.size() > 0)
10915     {
10916       int nodeId = 0;
10917       const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
10918       if (startNode)
10919         nodeId = startNode->GetID();
10920       MESSAGE("nodeId " << nodeId);
10921
10922       double radius2 = radius*radius;
10923       MESSAGE("radius2 " << radius2);
10924
10925       // --- volumes on start node
10926
10927       setOfVolToCheck.clear();
10928       SMDS_MeshElement* startVol = 0;
10929       SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
10930       while (volItr->more())
10931         {
10932           startVol = (SMDS_MeshElement*)volItr->next();
10933           setOfVolToCheck.insert(startVol->getVtkId());
10934         }
10935       if (setOfVolToCheck.empty())
10936         {
10937           MESSAGE("No volumes found");
10938           return;
10939         }
10940
10941       // --- starting with central volumes then their neighbors, check if they are inside
10942       //     or outside the domain, until no more new neighbor volume is inside.
10943       //     Fill the group of inside volumes
10944
10945       std::map<int, double> mapOfNodeDistance2;
10946       mapOfNodeDistance2.clear();
10947       std::set<int> setOfOutsideVol;
10948       while (!setOfVolToCheck.empty())
10949         {
10950           std::set<int>::iterator it = setOfVolToCheck.begin();
10951           int vtkId = *it;
10952           MESSAGE("volume to check,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
10953           bool volInside = false;
10954           vtkIdType npts = 0;
10955           vtkIdType* pts = 0;
10956           grid->GetCellPoints(vtkId, npts, pts);
10957           for (int i=0; i<npts; i++)
10958             {
10959               double distance2 = 0;
10960               if (mapOfNodeDistance2.count(pts[i]))
10961                 {
10962                   distance2 = mapOfNodeDistance2[pts[i]];
10963                   MESSAGE("point " << pts[i] << " distance2 " << distance2);
10964                 }
10965               else
10966                 {
10967                   double *coords = grid->GetPoint(pts[i]);
10968                   gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
10969                   distance2 = 1.E40;
10970                   for (int j=0; j<gpnts.size(); j++)
10971                     {
10972                       double d2 = aPoint.SquareDistance(gpnts[j]);
10973                       if (d2 < distance2)
10974                         {
10975                           distance2 = d2;
10976                           if (distance2 < radius2)
10977                             break;
10978                         }
10979                     }
10980                   mapOfNodeDistance2[pts[i]] = distance2;
10981                   MESSAGE("  point "  << pts[i]  << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " <<  coords[2]);
10982                 }
10983               if (distance2 < radius2)
10984                 {
10985                   volInside = true; // one or more nodes inside the domain
10986                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
10987                   break;
10988                 }
10989             }
10990           if (volInside)
10991             {
10992               setOfInsideVol.insert(vtkId);
10993               MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
10994               int neighborsVtkIds[NBMAXNEIGHBORS];
10995               int downIds[NBMAXNEIGHBORS];
10996               unsigned char downTypes[NBMAXNEIGHBORS];
10997               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10998               for (int n = 0; n < nbNeighbors; n++)
10999                 if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n]))
11000                   setOfVolToCheck.insert(neighborsVtkIds[n]);
11001             }
11002           else
11003             {
11004               setOfOutsideVol.insert(vtkId);
11005               MESSAGE("  volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11006             }
11007           setOfVolToCheck.erase(vtkId);
11008         }
11009     }
11010
11011   // --- for outside hexahedrons, check if they have more than one neighbor volume inside
11012   //     If yes, add the volume to the inside set
11013
11014   bool addedInside = true;
11015   std::set<int> setOfVolToReCheck;
11016   while (addedInside)
11017     {
11018       MESSAGE(" --------------------------- re check");
11019       addedInside = false;
11020       std::set<int>::iterator itv = setOfInsideVol.begin();
11021       for (; itv != setOfInsideVol.end(); ++itv)
11022         {
11023           int vtkId = *itv;
11024           int neighborsVtkIds[NBMAXNEIGHBORS];
11025           int downIds[NBMAXNEIGHBORS];
11026           unsigned char downTypes[NBMAXNEIGHBORS];
11027           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11028           for (int n = 0; n < nbNeighbors; n++)
11029             if (!setOfInsideVol.count(neighborsVtkIds[n]))
11030               setOfVolToReCheck.insert(neighborsVtkIds[n]);
11031         }
11032       setOfVolToCheck = setOfVolToReCheck;
11033       setOfVolToReCheck.clear();
11034       while  (!setOfVolToCheck.empty())
11035         {
11036           std::set<int>::iterator it = setOfVolToCheck.begin();
11037           int vtkId = *it;
11038           if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON)
11039             {
11040               MESSAGE("volume to recheck,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11041               int countInside = 0;
11042               int neighborsVtkIds[NBMAXNEIGHBORS];
11043               int downIds[NBMAXNEIGHBORS];
11044               unsigned char downTypes[NBMAXNEIGHBORS];
11045               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11046               for (int n = 0; n < nbNeighbors; n++)
11047                 if (setOfInsideVol.count(neighborsVtkIds[n]))
11048                   countInside++;
11049               MESSAGE("countInside " << countInside);
11050               if (countInside > 1)
11051                 {
11052                   MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11053                   setOfInsideVol.insert(vtkId);
11054                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
11055                   addedInside = true;
11056                 }
11057               else
11058                 setOfVolToReCheck.insert(vtkId);
11059             }
11060           setOfVolToCheck.erase(vtkId);
11061         }
11062     }
11063
11064   // --- map of Downward faces at the boundary, inside the global volume
11065   //     map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin)
11066   //     fill group of SMDS faces inside the volume (when several volume shapes)
11067   //     fill group of SMDS faces on the skin of the global volume (if skin)
11068
11069   std::map<DownIdType, int, DownIdCompare> boundaryFaces; // boundary faces inside the volume --> corresponding cell
11070   std::map<DownIdType, int, DownIdCompare> skinFaces;     // faces on the skin of the global volume --> corresponding cell
11071   std::set<int>::iterator it = setOfInsideVol.begin();
11072   for (; it != setOfInsideVol.end(); ++it)
11073     {
11074       int vtkId = *it;
11075       //MESSAGE("  vtkId " << vtkId  << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11076       int neighborsVtkIds[NBMAXNEIGHBORS];
11077       int downIds[NBMAXNEIGHBORS];
11078       unsigned char downTypes[NBMAXNEIGHBORS];
11079       int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true);
11080       for (int n = 0; n < nbNeighbors; n++)
11081         {
11082           int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n]));
11083           if (neighborDim == 3)
11084             {
11085               if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary
11086                 {
11087                   DownIdType face(downIds[n], downTypes[n]);
11088                   boundaryFaces[face] = vtkId;
11089                 }
11090               // if the face between to volumes is in the mesh, get it (internal face between shapes)
11091               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
11092               if (vtkFaceId >= 0)
11093                 {
11094                   sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId));
11095                   // find also the smds edges on this face
11096                   int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]);
11097                   const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]);
11098                   const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]);
11099                   for (int i = 0; i < nbEdges; i++)
11100                     {
11101                       int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]);
11102                       if (vtkEdgeId >= 0)
11103                         sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId));
11104                     }
11105                 }
11106             }
11107           else if (neighborDim == 2) // skin of the volume
11108             {
11109               DownIdType face(downIds[n], downTypes[n]);
11110               skinFaces[face] = vtkId;
11111               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
11112               if (vtkFaceId >= 0)
11113                 sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId));
11114             }
11115         }
11116     }
11117
11118   // --- identify the edges constituting the wire of each subshape on the skin
11119   //     define polylines with the nodes of edges, equivalent to wires
11120   //     project polylines on subshapes, and partition, to get geom faces
11121
11122   std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
11123   std::set<int> emptySet;
11124   emptySet.clear();
11125   std::set<int> shapeIds;
11126
11127   SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
11128   while (itelem->more())
11129     {
11130       const SMDS_MeshElement *elem = itelem->next();
11131       int shapeId = elem->getshapeId();
11132       int vtkId = elem->getVtkId();
11133       if (!shapeIdToVtkIdSet.count(shapeId))
11134         {
11135           shapeIdToVtkIdSet[shapeId] = emptySet;
11136           shapeIds.insert(shapeId);
11137         }
11138       shapeIdToVtkIdSet[shapeId].insert(vtkId);
11139     }
11140
11141   std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
11142   std::set<DownIdType, DownIdCompare> emptyEdges;
11143   emptyEdges.clear();
11144
11145   std::map<int, std::set<int> >::iterator itShape =  shapeIdToVtkIdSet.begin();
11146   for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
11147     {
11148       int shapeId = itShape->first;
11149       MESSAGE(" --- Shape ID --- "<< shapeId);
11150       shapeIdToEdges[shapeId] = emptyEdges;
11151
11152       std::vector<int> nodesEdges;
11153
11154       std::set<int>::iterator its = itShape->second.begin();
11155       for (; its != itShape->second.end(); ++its)
11156         {
11157           int vtkId = *its;
11158           MESSAGE("     " << vtkId);
11159           int neighborsVtkIds[NBMAXNEIGHBORS];
11160           int downIds[NBMAXNEIGHBORS];
11161           unsigned char downTypes[NBMAXNEIGHBORS];
11162           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11163           for (int n = 0; n < nbNeighbors; n++)
11164             {
11165               if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
11166                 continue;
11167               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
11168               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11169               if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
11170                 {
11171                   DownIdType edge(downIds[n], downTypes[n]);
11172                   if (!shapeIdToEdges[shapeId].count(edge))
11173                     {
11174                       shapeIdToEdges[shapeId].insert(edge);
11175                       int vtkNodeId[3];
11176                       int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId);
11177                       nodesEdges.push_back(vtkNodeId[0]);
11178                       nodesEdges.push_back(vtkNodeId[nbNodes-1]);
11179                       MESSAGE("       --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1);
11180                     }
11181                 }
11182             }
11183         }
11184
11185       std::list<int> order;
11186       order.clear();
11187       if (nodesEdges.size() > 0)
11188         {
11189           order.push_back(nodesEdges[0]); MESSAGE("       --- back " << order.back()+1); // SMDS id = VTK id + 1;
11190           nodesEdges[0] = -1;
11191           order.push_back(nodesEdges[1]); MESSAGE("       --- back " << order.back()+1);
11192           nodesEdges[1] = -1; // do not reuse this edge
11193           bool found = true;
11194           while (found)
11195             {
11196               int nodeTofind = order.back(); // try first to push back
11197               int i = 0;
11198               for (i = 0; i<nodesEdges.size(); i++)
11199                 if (nodesEdges[i] == nodeTofind)
11200                   break;
11201               if (i == nodesEdges.size())
11202                 found = false; // no follower found on back
11203               else
11204                 {
11205                   if (i%2) // odd ==> use the previous one
11206                     if (nodesEdges[i-1] < 0)
11207                       found = false;
11208                     else
11209                       {
11210                         order.push_back(nodesEdges[i-1]); MESSAGE("       --- back " << order.back()+1);
11211                         nodesEdges[i-1] = -1;
11212                       }
11213                   else // even ==> use the next one
11214                     if (nodesEdges[i+1] < 0)
11215                       found = false;
11216                     else
11217                       {
11218                         order.push_back(nodesEdges[i+1]); MESSAGE("       --- back " << order.back()+1);
11219                         nodesEdges[i+1] = -1;
11220                       }
11221                 }
11222               if (found)
11223                 continue;
11224               // try to push front
11225               found = true;
11226               nodeTofind = order.front(); // try to push front
11227               for (i = 0; i<nodesEdges.size(); i++)
11228                 if (nodesEdges[i] == nodeTofind)
11229                   break;
11230               if (i == nodesEdges.size())
11231                 {
11232                   found = false; // no predecessor found on front
11233                   continue;
11234                 }
11235               if (i%2) // odd ==> use the previous one
11236                 if (nodesEdges[i-1] < 0)
11237                   found = false;
11238                 else
11239                   {
11240                     order.push_front(nodesEdges[i-1]); MESSAGE("       --- front " << order.front()+1);
11241                     nodesEdges[i-1] = -1;
11242                   }
11243               else // even ==> use the next one
11244                 if (nodesEdges[i+1] < 0)
11245                   found = false;
11246                 else
11247                   {
11248                     order.push_front(nodesEdges[i+1]); MESSAGE("       --- front " << order.front()+1);
11249                     nodesEdges[i+1] = -1;
11250                   }
11251             }
11252         }
11253
11254
11255       std::vector<int> nodes;
11256       nodes.push_back(shapeId);
11257       std::list<int>::iterator itl = order.begin();
11258       for (; itl != order.end(); itl++)
11259         {
11260           nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
11261           MESSAGE("              ordered node " << nodes[nodes.size()-1]);
11262         }
11263       listOfListOfNodes.push_back(nodes);
11264     }
11265
11266   //     partition geom faces with blocFissure
11267   //     mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose)
11268   //     mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose)
11269
11270   return;
11271 }
11272
11273
11274 //================================================================================
11275 /*!
11276  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11277  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11278  * \return TRUE if operation has been completed successfully, FALSE otherwise
11279  */
11280 //================================================================================
11281
11282 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11283 {
11284   // iterates on volume elements and detect all free faces on them
11285   SMESHDS_Mesh* aMesh = GetMeshDS();
11286   if (!aMesh)
11287     return false;
11288   //bool res = false;
11289   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11290   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11291   while(vIt->more())
11292   {
11293     const SMDS_MeshVolume* volume = vIt->next();
11294     SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
11295     vTool.SetExternalNormal();
11296     //const bool isPoly = volume->IsPoly();
11297     const int iQuad = volume->IsQuadratic();
11298     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11299     {
11300       if (!vTool.IsFreeFace(iface))
11301         continue;
11302       nbFree++;
11303       vector<const SMDS_MeshNode *> nodes;
11304       int nbFaceNodes = vTool.NbFaceNodes(iface);
11305       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11306       int inode = 0;
11307       for ( ; inode < nbFaceNodes; inode += iQuad+1)
11308         nodes.push_back(faceNodes[inode]);
11309       if (iQuad) { // add medium nodes
11310         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11311           nodes.push_back(faceNodes[inode]);
11312         if ( nbFaceNodes == 9 ) // bi-quadratic quad
11313           nodes.push_back(faceNodes[8]);
11314       }
11315       // add new face based on volume nodes
11316       if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
11317         nbExisted++;
11318         continue; // face already exsist
11319       }
11320       AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
11321       nbCreated++;
11322     }
11323   }
11324   return ( nbFree==(nbExisted+nbCreated) );
11325 }
11326
11327 namespace
11328 {
11329   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11330   {
11331     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11332       return n;
11333     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11334   }
11335 }
11336 //================================================================================
11337 /*!
11338  * \brief Creates missing boundary elements
11339  *  \param elements - elements whose boundary is to be checked
11340  *  \param dimension - defines type of boundary elements to create
11341  *  \param group - a group to store created boundary elements in
11342  *  \param targetMesh - a mesh to store created boundary elements in
11343  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11344  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
11345  *                                boundary elements will be copied into the targetMesh
11346  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11347  *                                boundary elements will be added into the new group
11348  *  \param aroundElements - if true, elements will be created on boundary of given
11349  *                          elements else, on boundary of the whole mesh.
11350  * \return nb of added boundary elements
11351  */
11352 //================================================================================
11353
11354 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11355                                        Bnd_Dimension           dimension,
11356                                        SMESH_Group*            group/*=0*/,
11357                                        SMESH_Mesh*             targetMesh/*=0*/,
11358                                        bool                    toCopyElements/*=false*/,
11359                                        bool                    toCopyExistingBoundary/*=false*/,
11360                                        bool                    toAddExistingBondary/*= false*/,
11361                                        bool                    aroundElements/*= false*/)
11362 {
11363   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11364   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11365   // hope that all elements are of the same type, do not check them all
11366   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11367     throw SALOME_Exception(LOCALIZED("wrong element type"));
11368
11369   if ( !targetMesh )
11370     toCopyElements = toCopyExistingBoundary = false;
11371
11372   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11373   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11374   int nbAddedBnd = 0;
11375
11376   // editor adding present bnd elements and optionally holding elements to add to the group
11377   SMESH_MeshEditor* presentEditor;
11378   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11379   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11380
11381   SMESH_MesherHelper helper( *myMesh );
11382   const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
11383   SMDS_VolumeTool vTool;
11384   TIDSortedElemSet avoidSet;
11385   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11386   int inode;
11387
11388   typedef vector<const SMDS_MeshNode*> TConnectivity;
11389
11390   SMDS_ElemIteratorPtr eIt;
11391   if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
11392   else                  eIt = elemSetIterator( elements );
11393
11394   while (eIt->more())
11395   {
11396     const SMDS_MeshElement* elem = eIt->next();
11397     const int              iQuad = elem->IsQuadratic();
11398
11399     // ------------------------------------------------------------------------------------
11400     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11401     // ------------------------------------------------------------------------------------
11402     vector<const SMDS_MeshElement*> presentBndElems;
11403     vector<TConnectivity>           missingBndElems;
11404     TConnectivity nodes, elemNodes;
11405     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
11406     {
11407       vTool.SetExternalNormal();
11408       const SMDS_MeshElement* otherVol = 0;
11409       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11410       {
11411         if ( !vTool.IsFreeFace(iface, &otherVol) &&
11412              ( !aroundElements || elements.count( otherVol )))
11413           continue;
11414         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11415         const int    nbFaceNodes = vTool.NbFaceNodes (iface);
11416         if ( missType == SMDSAbs_Edge ) // boundary edges
11417         {
11418           nodes.resize( 2+iQuad );
11419           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11420           {
11421             for ( int j = 0; j < nodes.size(); ++j )
11422               nodes[j] =nn[i+j];
11423             if ( const SMDS_MeshElement* edge =
11424                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11425               presentBndElems.push_back( edge );
11426             else
11427               missingBndElems.push_back( nodes );
11428           }
11429         }
11430         else // boundary face
11431         {
11432           nodes.clear();
11433           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11434             nodes.push_back( nn[inode] ); // add corner nodes
11435           if (iQuad)
11436             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11437               nodes.push_back( nn[inode] ); // add medium nodes
11438           int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
11439           if ( iCenter > 0 )
11440             nodes.push_back( vTool.GetNodes()[ iCenter ] );
11441
11442           if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
11443                                                                SMDSAbs_Face, /*noMedium=*/false ))
11444             presentBndElems.push_back( f );
11445           else
11446             missingBndElems.push_back( nodes );
11447
11448           if ( targetMesh != myMesh )
11449           {
11450             // add 1D elements on face boundary to be added to a new mesh
11451             const SMDS_MeshElement* edge;
11452             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11453             {
11454               if ( iQuad )
11455                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11456               else
11457                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11458               if ( edge && avoidSet.insert( edge ).second )
11459                 presentBndElems.push_back( edge );
11460             }
11461           }
11462         }
11463       }
11464     }
11465     else if ( elem->GetType() == SMDSAbs_Face ) // elem is a face ------------------------
11466     {
11467       avoidSet.clear(), avoidSet.insert( elem );
11468       elemNodes.assign( SMDS_MeshElement::iterator( elem->interlacedNodesElemIterator() ),
11469                         SMDS_MeshElement::iterator() );
11470       elemNodes.push_back( elemNodes[0] );
11471       nodes.resize( 2 + iQuad );
11472       const int nbLinks = elem->NbCornerNodes();
11473       for ( int i = 0, iN = 0; i < nbLinks; i++, iN += 1+iQuad )
11474       {
11475         nodes[0] = elemNodes[iN];
11476         nodes[1] = elemNodes[iN+1+iQuad];
11477         if ( SMESH_MeshAlgos::FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11478           continue; // not free link
11479
11480         if ( iQuad ) nodes[2] = elemNodes[iN+1];
11481         if ( const SMDS_MeshElement* edge =
11482              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11483           presentBndElems.push_back( edge );
11484         else
11485           missingBndElems.push_back( nodes );
11486       }
11487     }
11488
11489     // ---------------------------------
11490     // 2. Add missing boundary elements
11491     // ---------------------------------
11492     if ( targetMesh != myMesh )
11493       // instead of making a map of nodes in this mesh and targetMesh,
11494       // we create nodes with same IDs.
11495       for ( int i = 0; i < missingBndElems.size(); ++i )
11496       {
11497         TConnectivity& srcNodes = missingBndElems[i];
11498         TConnectivity  nodes( srcNodes.size() );
11499         for ( inode = 0; inode < nodes.size(); ++inode )
11500           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11501         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11502                                                                    missType,
11503                                                                    /*noMedium=*/false))
11504           continue;
11505         tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11506         ++nbAddedBnd;
11507       }
11508     else
11509       for ( int i = 0; i < missingBndElems.size(); ++i )
11510       {
11511         TConnectivity& nodes = missingBndElems[i];
11512         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11513                                                                    missType,
11514                                                                    /*noMedium=*/false))
11515           continue;
11516         SMDS_MeshElement* elem =
11517           tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11518         ++nbAddedBnd;
11519
11520         // try to set a new element to a shape
11521         if ( myMesh->HasShapeToMesh() )
11522         {
11523           bool ok = true;
11524           set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
11525           const int nbN = nodes.size() / (iQuad+1 );
11526           for ( inode = 0; inode < nbN && ok; ++inode )
11527           {
11528             pair<int, TopAbs_ShapeEnum> i_stype =
11529               helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
11530             if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
11531               mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
11532           }
11533           if ( ok && mediumShapes.size() > 1 )
11534           {
11535             set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
11536             pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
11537             for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
11538             {
11539               if (( ok = ( stype_i->first != stype_i_0.first )))
11540                 ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
11541                                         aMesh->IndexToShape( stype_i_0.second ));
11542             }
11543           }
11544           if ( ok && mediumShapes.begin()->first == missShapeType )
11545             aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
11546         }
11547       }
11548
11549     // ----------------------------------
11550     // 3. Copy present boundary elements
11551     // ----------------------------------
11552     if ( toCopyExistingBoundary )
11553       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11554       {
11555         const SMDS_MeshElement* e = presentBndElems[i];
11556         TConnectivity nodes( e->NbNodes() );
11557         for ( inode = 0; inode < nodes.size(); ++inode )
11558           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11559         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11560       }
11561     else // store present elements to add them to a group
11562       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11563       {
11564         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11565       }
11566
11567   } // loop on given elements
11568
11569   // ---------------------------------------------
11570   // 4. Fill group with boundary elements
11571   // ---------------------------------------------
11572   if ( group )
11573   {
11574     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11575       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11576         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11577   }
11578   tgtEditor.myLastCreatedElems.Clear();
11579   tgtEditor2.myLastCreatedElems.Clear();
11580
11581   // -----------------------
11582   // 5. Copy given elements
11583   // -----------------------
11584   if ( toCopyElements && targetMesh != myMesh )
11585   {
11586     if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
11587     else                  eIt = elemSetIterator( elements );
11588     while (eIt->more())
11589     {
11590       const SMDS_MeshElement* elem = eIt->next();
11591       TConnectivity nodes( elem->NbNodes() );
11592       for ( inode = 0; inode < nodes.size(); ++inode )
11593         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11594       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11595
11596       tgtEditor.myLastCreatedElems.Clear();
11597     }
11598   }
11599   return nbAddedBnd;
11600 }