Salome HOME
avoid compilation warnings in release mode
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File      : SMESH_MeshEditor.cxx
24 // Created   : Mon Apr 12 16:10:22 2004
25 // Author    : Edward AGAPOV (eap)
26
27 #include "SMESH_MeshEditor.hxx"
28
29 #include "SMDS_FaceOfNodes.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_EdgePosition.hxx"
32 #include "SMDS_FacePosition.hxx"
33 #include "SMDS_SpacePosition.hxx"
34 #include "SMDS_MeshGroup.hxx"
35 #include "SMDS_LinearEdge.hxx"
36 #include "SMDS_Downward.hxx"
37 #include "SMDS_SetIterator.hxx"
38
39 #include "SMESHDS_Group.hxx"
40 #include "SMESHDS_Mesh.hxx"
41
42 #include "SMESH_Algo.hxx"
43 #include "SMESH_ControlsDef.hxx"
44 #include "SMESH_Group.hxx"
45 #include "SMESH_MeshAlgos.hxx"
46 #include "SMESH_MesherHelper.hxx"
47 #include "SMESH_OctreeNode.hxx"
48 #include "SMESH_subMesh.hxx"
49
50 #include <Basics_OCCTVersion.hxx>
51
52 #include "utilities.h"
53
54 #include <BRepAdaptor_Surface.hxx>
55 #include <BRepBuilderAPI_MakeEdge.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
58 #include <ElCLib.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <Geom2d_Curve.hxx>
63 #include <GeomAdaptor_Surface.hxx>
64 #include <Geom_Curve.hxx>
65 #include <Geom_Surface.hxx>
66 #include <Precision.hxx>
67 #include <TColStd_ListOfInteger.hxx>
68 #include <TopAbs_State.hxx>
69 #include <TopExp.hxx>
70 #include <TopExp_Explorer.hxx>
71 #include <TopTools_ListIteratorOfListOfShape.hxx>
72 #include <TopTools_ListOfShape.hxx>
73 #include <TopTools_SequenceOfShape.hxx>
74 #include <TopoDS.hxx>
75 #include <TopoDS_Face.hxx>
76 #include <TopoDS_Solid.hxx>
77 #include <gp.hxx>
78 #include <gp_Ax1.hxx>
79 #include <gp_Dir.hxx>
80 #include <gp_Lin.hxx>
81 #include <gp_Pln.hxx>
82 #include <gp_Trsf.hxx>
83 #include <gp_Vec.hxx>
84 #include <gp_XY.hxx>
85 #include <gp_XYZ.hxx>
86
87 #include <cmath>
88
89 #include <map>
90 #include <set>
91 #include <numeric>
92 #include <limits>
93 #include <algorithm>
94 #include <sstream>
95
96 #include <boost/tuple/tuple.hpp>
97
98 #include <Standard_Failure.hxx>
99 #include <Standard_ErrorHandler.hxx>
100
101 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
102
103 using namespace std;
104 using namespace SMESH::Controls;
105
106 namespace
107 {
108   template < class ELEM_SET >
109   SMDS_ElemIteratorPtr elemSetIterator( const ELEM_SET& elements )
110   {
111     typedef SMDS_SetIterator
112       < SMDS_pElement, typename ELEM_SET::const_iterator> TSetIterator;
113     return SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
114   }
115 }
116
117 //=======================================================================
118 //function : SMESH_MeshEditor
119 //purpose  :
120 //=======================================================================
121
122 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
123   :myMesh( theMesh ) // theMesh may be NULL
124 {
125 }
126
127 //================================================================================
128 /*!
129  * \brief Clears myLastCreatedNodes and myLastCreatedElems
130  */
131 //================================================================================
132
133 void SMESH_MeshEditor::CrearLastCreated()
134 {
135   myLastCreatedNodes.Clear();
136   myLastCreatedElems.Clear();
137 }
138
139
140 //=======================================================================
141 /*!
142  * \brief Add element
143  */
144 //=======================================================================
145
146 SMDS_MeshElement*
147 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
148                              const SMDSAbs_ElementType            type,
149                              const bool                           isPoly,
150                              const int                            ID,
151                              const double                         ballDiameter)
152 {
153   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
154   SMDS_MeshElement* e = 0;
155   int nbnode = node.size();
156   SMESHDS_Mesh* mesh = GetMeshDS();
157   switch ( type ) {
158   case SMDSAbs_Face:
159     if ( !isPoly ) {
160       if      (nbnode == 3) {
161         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
162         else           e = mesh->AddFace      (node[0], node[1], node[2] );
163       }
164       else if (nbnode == 4) {
165         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
166         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
167       }
168       else if (nbnode == 6) {
169         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
170                                                node[4], node[5], ID);
171         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
172                                                node[4], node[5] );
173       }
174       else if (nbnode == 7) {
175         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
176                                                node[4], node[5], node[6], ID);
177         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
178                                                node[4], node[5], node[6] );
179       }
180       else if (nbnode == 8) {
181         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
182                                                node[4], node[5], node[6], node[7], ID);
183         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
184                                                node[4], node[5], node[6], node[7] );
185       }
186       else if (nbnode == 9) {
187         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
188                                                node[4], node[5], node[6], node[7], node[8], ID);
189         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
190                                                node[4], node[5], node[6], node[7], node[8] );
191       }
192     } else {
193       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
194       else           e = mesh->AddPolygonalFace      (node    );
195     }
196     break;
197
198   case SMDSAbs_Volume:
199     if ( !isPoly ) {
200       if      (nbnode == 4) {
201         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
202         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
203       }
204       else if (nbnode == 5) {
205         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
206                                                  node[4], ID);
207         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
208                                                  node[4] );
209       }
210       else if (nbnode == 6) {
211         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
212                                                  node[4], node[5], ID);
213         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
214                                                  node[4], node[5] );
215       }
216       else if (nbnode == 8) {
217         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
218                                                  node[4], node[5], node[6], node[7], ID);
219         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
220                                                  node[4], node[5], node[6], node[7] );
221       }
222       else if (nbnode == 10) {
223         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
224                                                  node[4], node[5], node[6], node[7],
225                                                  node[8], node[9], ID);
226         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
227                                                  node[4], node[5], node[6], node[7],
228                                                  node[8], node[9] );
229       }
230       else if (nbnode == 12) {
231         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
232                                                  node[4], node[5], node[6], node[7],
233                                                  node[8], node[9], node[10], node[11], ID);
234         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
235                                                  node[4], node[5], node[6], node[7],
236                                                  node[8], node[9], node[10], node[11] );
237       }
238       else if (nbnode == 13) {
239         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
240                                                  node[4], node[5], node[6], node[7],
241                                                  node[8], node[9], node[10],node[11],
242                                                  node[12],ID);
243         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
244                                                  node[4], node[5], node[6], node[7],
245                                                  node[8], node[9], node[10],node[11],
246                                                  node[12] );
247       }
248       else if (nbnode == 15) {
249         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
250                                                  node[4], node[5], node[6], node[7],
251                                                  node[8], node[9], node[10],node[11],
252                                                  node[12],node[13],node[14],ID);
253         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
254                                                  node[4], node[5], node[6], node[7],
255                                                  node[8], node[9], node[10],node[11],
256                                                  node[12],node[13],node[14] );
257       }
258       else if (nbnode == 20) {
259         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
260                                                  node[4], node[5], node[6], node[7],
261                                                  node[8], node[9], node[10],node[11],
262                                                  node[12],node[13],node[14],node[15],
263                                                  node[16],node[17],node[18],node[19],ID);
264         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
265                                                  node[4], node[5], node[6], node[7],
266                                                  node[8], node[9], node[10],node[11],
267                                                  node[12],node[13],node[14],node[15],
268                                                  node[16],node[17],node[18],node[19] );
269       }
270       else if (nbnode == 27) {
271         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
272                                                  node[4], node[5], node[6], node[7],
273                                                  node[8], node[9], node[10],node[11],
274                                                  node[12],node[13],node[14],node[15],
275                                                  node[16],node[17],node[18],node[19],
276                                                  node[20],node[21],node[22],node[23],
277                                                  node[24],node[25],node[26], ID);
278         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
279                                                  node[4], node[5], node[6], node[7],
280                                                  node[8], node[9], node[10],node[11],
281                                                  node[12],node[13],node[14],node[15],
282                                                  node[16],node[17],node[18],node[19],
283                                                  node[20],node[21],node[22],node[23],
284                                                  node[24],node[25],node[26] );
285       }
286     }
287     break;
288
289   case SMDSAbs_Edge:
290     if ( nbnode == 2 ) {
291       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
292       else           e = mesh->AddEdge      (node[0], node[1] );
293     }
294     else if ( nbnode == 3 ) {
295       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
296       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
297     }
298     break;
299
300   case SMDSAbs_0DElement:
301     if ( nbnode == 1 ) {
302       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
303       else           e = mesh->Add0DElement      (node[0] );
304     }
305     break;
306
307   case SMDSAbs_Node:
308     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
309     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
310     break;
311
312   case SMDSAbs_Ball:
313     if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], ballDiameter, ID);
314     else           e = mesh->AddBall      (node[0], ballDiameter);
315     break;
316
317   default:;
318   }
319   if ( e ) myLastCreatedElems.Append( e );
320   return e;
321 }
322
323 //=======================================================================
324 /*!
325  * \brief Add element
326  */
327 //=======================================================================
328
329 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
330                                                const SMDSAbs_ElementType type,
331                                                const bool                isPoly,
332                                                const int                 ID)
333 {
334   vector<const SMDS_MeshNode*> nodes;
335   nodes.reserve( nodeIDs.size() );
336   vector<int>::const_iterator id = nodeIDs.begin();
337   while ( id != nodeIDs.end() ) {
338     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
339       nodes.push_back( node );
340     else
341       return 0;
342   }
343   return AddElement( nodes, type, isPoly, ID );
344 }
345
346 //=======================================================================
347 //function : Remove
348 //purpose  : Remove a node or an element.
349 //           Modify a compute state of sub-meshes which become empty
350 //=======================================================================
351
352 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
353                               const bool         isNodes )
354 {
355   myLastCreatedElems.Clear();
356   myLastCreatedNodes.Clear();
357
358   SMESHDS_Mesh* aMesh = GetMeshDS();
359   set< SMESH_subMesh *> smmap;
360
361   int removed = 0;
362   list<int>::const_iterator it = theIDs.begin();
363   for ( ; it != theIDs.end(); it++ ) {
364     const SMDS_MeshElement * elem;
365     if ( isNodes )
366       elem = aMesh->FindNode( *it );
367     else
368       elem = aMesh->FindElement( *it );
369     if ( !elem )
370       continue;
371
372     // Notify VERTEX sub-meshes about modification
373     if ( isNodes ) {
374       const SMDS_MeshNode* node = cast2Node( elem );
375       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
376         if ( int aShapeID = node->getshapeId() )
377           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
378             smmap.insert( sm );
379     }
380     // Find sub-meshes to notify about modification
381     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
382     //     while ( nodeIt->more() ) {
383     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
384     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
385     //       if ( aPosition.get() ) {
386     //         if ( int aShapeID = aPosition->GetShapeId() ) {
387     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
388     //             smmap.insert( sm );
389     //         }
390     //       }
391     //     }
392
393     // Do remove
394     if ( isNodes )
395       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
396     else
397       aMesh->RemoveElement( elem );
398     removed++;
399   }
400
401   // Notify sub-meshes about modification
402   if ( !smmap.empty() ) {
403     set< SMESH_subMesh *>::iterator smIt;
404     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
405       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
406   }
407
408   //   // Check if the whole mesh becomes empty
409   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
410   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
411
412   return removed;
413 }
414
415 //================================================================================
416 /*!
417  * \brief Create 0D elements on all nodes of the given object except those
418  *        nodes on which a 0D element already exists.
419  *  \param elements - Elements on whose nodes to create 0D elements; if empty, 
420  *                    the all mesh is treated
421  *  \param all0DElems - returns all 0D elements found or created on nodes of \a elements
422  */
423 //================================================================================
424
425 void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements,
426                                                    TIDSortedElemSet&       all0DElems )
427 {
428   SMDS_ElemIteratorPtr elemIt;
429   vector< const SMDS_MeshElement* > allNodes;
430   if ( elements.empty() )
431   {
432     allNodes.reserve( GetMeshDS()->NbNodes() );
433     elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node );
434     while ( elemIt->more() )
435       allNodes.push_back( elemIt->next() );
436
437     elemIt = elemSetIterator( allNodes );
438   }
439   else
440   {
441     elemIt = elemSetIterator( elements );
442   }
443
444   while ( elemIt->more() )
445   {
446     const SMDS_MeshElement* e = elemIt->next();
447     SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
448     while ( nodeIt->more() )
449     {
450       const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
451       SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement );
452       if ( it0D->more() )
453         all0DElems.insert( it0D->next() );
454       else {
455         myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n ));
456         all0DElems.insert( myLastCreatedElems.Last() );
457       }
458     }
459   }
460 }
461
462 //=======================================================================
463 //function : FindShape
464 //purpose  : Return an index of the shape theElem is on
465 //           or zero if a shape not found
466 //=======================================================================
467
468 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
469 {
470   myLastCreatedElems.Clear();
471   myLastCreatedNodes.Clear();
472
473   SMESHDS_Mesh * aMesh = GetMeshDS();
474   if ( aMesh->ShapeToMesh().IsNull() )
475     return 0;
476
477   int aShapeID = theElem->getshapeId();
478   if ( aShapeID < 1 )
479     return 0;
480
481   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
482     if ( sm->Contains( theElem ))
483       return aShapeID;
484
485   if ( theElem->GetType() == SMDSAbs_Node ) {
486     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
487   }
488   else {
489     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
490   }
491
492   TopoDS_Shape aShape; // the shape a node of theElem is on
493   if ( theElem->GetType() != SMDSAbs_Node )
494   {
495     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
496     while ( nodeIt->more() ) {
497       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
498       if ((aShapeID = node->getshapeId()) > 0) {
499         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
500           if ( sm->Contains( theElem ))
501             return aShapeID;
502           if ( aShape.IsNull() )
503             aShape = aMesh->IndexToShape( aShapeID );
504         }
505       }
506     }
507   }
508
509   // None of nodes is on a proper shape,
510   // find the shape among ancestors of aShape on which a node is
511   if ( !aShape.IsNull() ) {
512     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
513     for ( ; ancIt.More(); ancIt.Next() ) {
514       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
515       if ( sm && sm->Contains( theElem ))
516         return aMesh->ShapeToIndex( ancIt.Value() );
517     }
518   }
519   else
520   {
521     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
522     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
523     for ( ; id_sm != id2sm.end(); ++id_sm )
524       if ( id_sm->second->Contains( theElem ))
525         return id_sm->first;
526   }
527
528   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
529   return 0;
530 }
531
532 //=======================================================================
533 //function : IsMedium
534 //purpose  :
535 //=======================================================================
536
537 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
538                                 const SMDSAbs_ElementType typeToCheck)
539 {
540   bool isMedium = false;
541   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
542   while (it->more() && !isMedium ) {
543     const SMDS_MeshElement* elem = it->next();
544     isMedium = elem->IsMediumNode(node);
545   }
546   return isMedium;
547 }
548
549 //=======================================================================
550 //function : shiftNodesQuadTria
551 //purpose  : Shift nodes in the array corresponded to quadratic triangle
552 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
553 //=======================================================================
554
555 static void shiftNodesQuadTria(vector< const SMDS_MeshNode* >& aNodes)
556 {
557   const SMDS_MeshNode* nd1 = aNodes[0];
558   aNodes[0] = aNodes[1];
559   aNodes[1] = aNodes[2];
560   aNodes[2] = nd1;
561   const SMDS_MeshNode* nd2 = aNodes[3];
562   aNodes[3] = aNodes[4];
563   aNodes[4] = aNodes[5];
564   aNodes[5] = nd2;
565 }
566
567 //=======================================================================
568 //function : nbEdgeConnectivity
569 //purpose  : return number of the edges connected with the theNode.
570 //           if theEdges has connections with the other type of the
571 //           elements, return -1
572 //=======================================================================
573
574 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
575 {
576   // SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
577   // int nb=0;
578   // while(elemIt->more()) {
579   //   elemIt->next();
580   //   nb++;
581   // }
582   // return nb;
583   return theNode->NbInverseElements();
584 }
585
586 //=======================================================================
587 //function : getNodesFromTwoTria
588 //purpose  : 
589 //=======================================================================
590
591 static bool getNodesFromTwoTria(const SMDS_MeshElement * theTria1,
592                                 const SMDS_MeshElement * theTria2,
593                                 vector< const SMDS_MeshNode*>& N1,
594                                 vector< const SMDS_MeshNode*>& N2)
595 {
596   N1.assign( theTria1->begin_nodes(), theTria1->end_nodes() );
597   if ( N1.size() < 6 ) return false;
598   N2.assign( theTria2->begin_nodes(), theTria2->end_nodes() );
599   if ( N2.size() < 6 ) return false;
600
601   int sames[3] = {-1,-1,-1};
602   int nbsames = 0;
603   int i, j;
604   for(i=0; i<3; i++) {
605     for(j=0; j<3; j++) {
606       if(N1[i]==N2[j]) {
607         sames[i] = j;
608         nbsames++;
609         break;
610       }
611     }
612   }
613   if(nbsames!=2) return false;
614   if(sames[0]>-1) {
615     shiftNodesQuadTria(N1);
616     if(sames[1]>-1) {
617       shiftNodesQuadTria(N1);
618     }
619   }
620   i = sames[0] + sames[1] + sames[2];
621   for(; i<2; i++) {
622     shiftNodesQuadTria(N2);
623   }
624   // now we receive following N1 and N2 (using numeration as in the image below)
625   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
626   // i.e. first nodes from both arrays form a new diagonal
627   return true;
628 }
629
630 //=======================================================================
631 //function : InverseDiag
632 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
633 //           but having other common link.
634 //           Return False if args are improper
635 //=======================================================================
636
637 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
638                                     const SMDS_MeshElement * theTria2 )
639 {
640   MESSAGE("InverseDiag");
641   myLastCreatedElems.Clear();
642   myLastCreatedNodes.Clear();
643
644   if (!theTria1 || !theTria2)
645     return false;
646
647   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
648   if (!F1) return false;
649   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
650   if (!F2) return false;
651   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
652       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
653
654     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
655     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
656     //    |/ |                                         | \|
657     //  B +--+ 2                                     B +--+ 2
658
659     // put nodes in array and find out indices of the same ones
660     const SMDS_MeshNode* aNodes [6];
661     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
662     int i = 0;
663     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
664     while ( it->more() ) {
665       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
666
667       if ( i > 2 ) // theTria2
668         // find same node of theTria1
669         for ( int j = 0; j < 3; j++ )
670           if ( aNodes[ i ] == aNodes[ j ]) {
671             sameInd[ j ] = i;
672             sameInd[ i ] = j;
673             break;
674           }
675       // next
676       i++;
677       if ( i == 3 ) {
678         if ( it->more() )
679           return false; // theTria1 is not a triangle
680         it = theTria2->nodesIterator();
681       }
682       if ( i == 6 && it->more() )
683         return false; // theTria2 is not a triangle
684     }
685
686     // find indices of 1,2 and of A,B in theTria1
687     int iA = 0, iB = 0, i1 = 0, i2 = 0;
688     for ( i = 0; i < 6; i++ ) {
689       if ( sameInd [ i ] == 0 ) {
690         if ( i < 3 ) i1 = i;
691         else         i2 = i;
692       }
693       else if (i < 3) {
694         if ( iA ) iB = i;
695         else      iA = i;
696       }
697     }
698     // nodes 1 and 2 should not be the same
699     if ( aNodes[ i1 ] == aNodes[ i2 ] )
700       return false;
701
702     // theTria1: A->2
703     aNodes[ iA ] = aNodes[ i2 ];
704     // theTria2: B->1
705     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
706
707     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
708     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
709
710     return true;
711
712   } // end if(F1 && F2)
713
714   // check case of quadratic faces
715   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle &&
716       theTria1->GetEntityType() != SMDSEntity_BiQuad_Triangle)
717     return false;
718   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle&&
719       theTria2->GetEntityType() != SMDSEntity_BiQuad_Triangle)
720     return false;
721
722   //       5
723   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
724   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
725   //    |   / |
726   //  7 +  +  + 6
727   //    | /9  |
728   //    |/    |
729   //  4 +--+--+ 3
730   //       8
731
732   vector< const SMDS_MeshNode* > N1;
733   vector< const SMDS_MeshNode* > N2;
734   if(!getNodesFromTwoTria(theTria1,theTria2,N1,N2))
735     return false;
736   // now we receive following N1 and N2 (using numeration as above image)
737   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
738   // i.e. first nodes from both arrays determ new diagonal
739
740   vector< const SMDS_MeshNode*> N1new( N1.size() );
741   vector< const SMDS_MeshNode*> N2new( N2.size() );
742   N1new.back() = N1.back(); // central node of biquadratic
743   N2new.back() = N2.back();
744   N1new[0] = N1[0];  N2new[0] = N1[0];
745   N1new[1] = N2[0];  N2new[1] = N1[1];
746   N1new[2] = N2[1];  N2new[2] = N2[0];
747   N1new[3] = N1[4];  N2new[3] = N1[3];
748   N1new[4] = N2[3];  N2new[4] = N2[5];
749   N1new[5] = N1[5];  N2new[5] = N1[4];
750   // change nodes in faces
751   GetMeshDS()->ChangeElementNodes( theTria1, &N1new[0], N1new.size() );
752   GetMeshDS()->ChangeElementNodes( theTria2, &N2new[0], N2new.size() );
753
754   // move the central node of biquadratic triangle
755   SMESH_MesherHelper helper( *GetMesh() );
756   for ( int is2nd = 0; is2nd < 2; ++is2nd )
757   {
758     const SMDS_MeshElement*         tria = is2nd ? theTria2 : theTria1;
759     vector< const SMDS_MeshNode*>& nodes = is2nd ? N2new : N1new;
760     if ( nodes.size() < 7 )
761       continue;
762     helper.SetSubShape( tria->getshapeId() );
763     const TopoDS_Face& F = TopoDS::Face( helper.GetSubShape() );
764     gp_Pnt xyz;
765     if ( F.IsNull() )
766     {
767       xyz = ( SMESH_TNodeXYZ( nodes[3] ) +
768               SMESH_TNodeXYZ( nodes[4] ) +
769               SMESH_TNodeXYZ( nodes[5] )) / 3.;
770     }
771     else
772     {
773       bool checkUV;
774       gp_XY uv = ( helper.GetNodeUV( F, nodes[3], nodes[2], &checkUV ) +
775                    helper.GetNodeUV( F, nodes[4], nodes[0], &checkUV ) +
776                    helper.GetNodeUV( F, nodes[5], nodes[1], &checkUV )) / 3.;
777       TopLoc_Location loc;
778       Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc);
779       xyz = S->Value( uv.X(), uv.Y() );
780       xyz.Transform( loc );
781       if ( nodes[6]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE &&  // set UV
782            nodes[6]->getshapeId() > 0 )
783         GetMeshDS()->SetNodeOnFace( nodes[6], nodes[6]->getshapeId(), uv.X(), uv.Y() );
784     }
785     GetMeshDS()->MoveNode( nodes[6], xyz.X(), xyz.Y(), xyz.Z() );
786   }
787   return true;
788 }
789
790 //=======================================================================
791 //function : findTriangles
792 //purpose  : find triangles sharing theNode1-theNode2 link
793 //=======================================================================
794
795 static bool findTriangles(const SMDS_MeshNode *    theNode1,
796                           const SMDS_MeshNode *    theNode2,
797                           const SMDS_MeshElement*& theTria1,
798                           const SMDS_MeshElement*& theTria2)
799 {
800   if ( !theNode1 || !theNode2 ) return false;
801
802   theTria1 = theTria2 = 0;
803
804   set< const SMDS_MeshElement* > emap;
805   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
806   while (it->more()) {
807     const SMDS_MeshElement* elem = it->next();
808     if ( elem->NbCornerNodes() == 3 )
809       emap.insert( elem );
810   }
811   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
812   while (it->more()) {
813     const SMDS_MeshElement* elem = it->next();
814     if ( emap.count( elem )) {
815       if ( !theTria1 )
816       {
817         theTria1 = elem;
818       }
819       else  
820       {
821         theTria2 = elem;
822         // theTria1 must be element with minimum ID
823         if ( theTria2->GetID() < theTria1->GetID() )
824           std::swap( theTria2, theTria1 );
825         return true;
826       }
827     }
828   }
829   return false;
830 }
831
832 //=======================================================================
833 //function : InverseDiag
834 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
835 //           with ones built on the same 4 nodes but having other common link.
836 //           Return false if proper faces not found
837 //=======================================================================
838
839 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
840                                     const SMDS_MeshNode * theNode2)
841 {
842   myLastCreatedElems.Clear();
843   myLastCreatedNodes.Clear();
844
845   MESSAGE( "::InverseDiag()" );
846
847   const SMDS_MeshElement *tr1, *tr2;
848   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
849     return false;
850
851   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
852   if (!F1) return false;
853   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
854   if (!F2) return false;
855   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
856       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
857
858     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
859     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
860     //    |/ |                                    | \|
861     //  B +--+ 2                                B +--+ 2
862
863     // put nodes in array
864     // and find indices of 1,2 and of A in tr1 and of B in tr2
865     int i, iA1 = 0, i1 = 0;
866     const SMDS_MeshNode* aNodes1 [3];
867     SMDS_ElemIteratorPtr it;
868     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
869       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
870       if ( aNodes1[ i ] == theNode1 )
871         iA1 = i; // node A in tr1
872       else if ( aNodes1[ i ] != theNode2 )
873         i1 = i;  // node 1
874     }
875     int iB2 = 0, i2 = 0;
876     const SMDS_MeshNode* aNodes2 [3];
877     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
878       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
879       if ( aNodes2[ i ] == theNode2 )
880         iB2 = i; // node B in tr2
881       else if ( aNodes2[ i ] != theNode1 )
882         i2 = i;  // node 2
883     }
884
885     // nodes 1 and 2 should not be the same
886     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
887       return false;
888
889     // tr1: A->2
890     aNodes1[ iA1 ] = aNodes2[ i2 ];
891     // tr2: B->1
892     aNodes2[ iB2 ] = aNodes1[ i1 ];
893
894     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
895     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
896
897     return true;
898   }
899
900   // check case of quadratic faces
901   return InverseDiag(tr1,tr2);
902 }
903
904 //=======================================================================
905 //function : getQuadrangleNodes
906 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
907 //           fusion of triangles tr1 and tr2 having shared link on
908 //           theNode1 and theNode2
909 //=======================================================================
910
911 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
912                         const SMDS_MeshNode *    theNode1,
913                         const SMDS_MeshNode *    theNode2,
914                         const SMDS_MeshElement * tr1,
915                         const SMDS_MeshElement * tr2 )
916 {
917   if( tr1->NbNodes() != tr2->NbNodes() )
918     return false;
919   // find the 4-th node to insert into tr1
920   const SMDS_MeshNode* n4 = 0;
921   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
922   int i=0;
923   while ( !n4 && i<3 ) {
924     const SMDS_MeshNode * n = cast2Node( it->next() );
925     i++;
926     bool isDiag = ( n == theNode1 || n == theNode2 );
927     if ( !isDiag )
928       n4 = n;
929   }
930   // Make an array of nodes to be in a quadrangle
931   int iNode = 0, iFirstDiag = -1;
932   it = tr1->nodesIterator();
933   i=0;
934   while ( i<3 ) {
935     const SMDS_MeshNode * n = cast2Node( it->next() );
936     i++;
937     bool isDiag = ( n == theNode1 || n == theNode2 );
938     if ( isDiag ) {
939       if ( iFirstDiag < 0 )
940         iFirstDiag = iNode;
941       else if ( iNode - iFirstDiag == 1 )
942         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
943     }
944     else if ( n == n4 ) {
945       return false; // tr1 and tr2 should not have all the same nodes
946     }
947     theQuadNodes[ iNode++ ] = n;
948   }
949   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
950     theQuadNodes[ iNode ] = n4;
951
952   return true;
953 }
954
955 //=======================================================================
956 //function : DeleteDiag
957 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
958 //           with a quadrangle built on the same 4 nodes.
959 //           Return false if proper faces not found
960 //=======================================================================
961
962 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
963                                    const SMDS_MeshNode * theNode2)
964 {
965   myLastCreatedElems.Clear();
966   myLastCreatedNodes.Clear();
967
968   MESSAGE( "::DeleteDiag()" );
969
970   const SMDS_MeshElement *tr1, *tr2;
971   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
972     return false;
973
974   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
975   if (!F1) return false;
976   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
977   if (!F2) return false;
978   SMESHDS_Mesh * aMesh = GetMeshDS();
979
980   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
981       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
982
983     const SMDS_MeshNode* aNodes [ 4 ];
984     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
985       return false;
986
987     const SMDS_MeshElement* newElem = 0;
988     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
989     myLastCreatedElems.Append(newElem);
990     AddToSameGroups( newElem, tr1, aMesh );
991     int aShapeId = tr1->getshapeId();
992     if ( aShapeId )
993       {
994         aMesh->SetMeshElementOnShape( newElem, aShapeId );
995       }
996     aMesh->RemoveElement( tr1 );
997     aMesh->RemoveElement( tr2 );
998
999     return true;
1000   }
1001
1002   // check case of quadratic faces
1003   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
1004     return false;
1005   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
1006     return false;
1007
1008   //       5
1009   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
1010   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
1011   //    |   / |
1012   //  7 +  +  + 6
1013   //    | /9  |
1014   //    |/    |
1015   //  4 +--+--+ 3
1016   //       8
1017
1018   vector< const SMDS_MeshNode* > N1;
1019   vector< const SMDS_MeshNode* > N2;
1020   if(!getNodesFromTwoTria(tr1,tr2,N1,N2))
1021     return false;
1022   // now we receive following N1 and N2 (using numeration as above image)
1023   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
1024   // i.e. first nodes from both arrays determ new diagonal
1025
1026   const SMDS_MeshNode* aNodes[8];
1027   aNodes[0] = N1[0];
1028   aNodes[1] = N1[1];
1029   aNodes[2] = N2[0];
1030   aNodes[3] = N2[1];
1031   aNodes[4] = N1[3];
1032   aNodes[5] = N2[5];
1033   aNodes[6] = N2[3];
1034   aNodes[7] = N1[5];
1035
1036   const SMDS_MeshElement* newElem = 0;
1037   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
1038                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
1039   myLastCreatedElems.Append(newElem);
1040   AddToSameGroups( newElem, tr1, aMesh );
1041   int aShapeId = tr1->getshapeId();
1042   if ( aShapeId )
1043     {
1044       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1045     }
1046   aMesh->RemoveElement( tr1 );
1047   aMesh->RemoveElement( tr2 );
1048
1049   // remove middle node (9)
1050   GetMeshDS()->RemoveNode( N1[4] );
1051
1052   return true;
1053 }
1054
1055 //=======================================================================
1056 //function : Reorient
1057 //purpose  : Reverse theElement orientation
1058 //=======================================================================
1059
1060 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
1061 {
1062   MESSAGE("Reorient");
1063   myLastCreatedElems.Clear();
1064   myLastCreatedNodes.Clear();
1065
1066   if (!theElem)
1067     return false;
1068   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
1069   if ( !it || !it->more() )
1070     return false;
1071
1072   const SMDSAbs_ElementType type = theElem->GetType();
1073   if ( type < SMDSAbs_Edge || type > SMDSAbs_Volume )
1074     return false;
1075
1076   const SMDSAbs_EntityType geomType = theElem->GetEntityType();
1077   if ( geomType == SMDSEntity_Polyhedra ) // polyhedron
1078   {
1079     const SMDS_VtkVolume* aPolyedre =
1080       dynamic_cast<const SMDS_VtkVolume*>( theElem );
1081     if (!aPolyedre) {
1082       MESSAGE("Warning: bad volumic element");
1083       return false;
1084     }
1085     const int nbFaces = aPolyedre->NbFaces();
1086     vector<const SMDS_MeshNode *> poly_nodes;
1087     vector<int> quantities (nbFaces);
1088
1089     // reverse each face of the polyedre
1090     for (int iface = 1; iface <= nbFaces; iface++) {
1091       int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1092       quantities[iface - 1] = nbFaceNodes;
1093
1094       for (inode = nbFaceNodes; inode >= 1; inode--) {
1095         const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1096         poly_nodes.push_back(curNode);
1097       }
1098     }
1099     return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1100   }
1101   else // other elements
1102   {
1103     vector<const SMDS_MeshNode*> nodes( theElem->begin_nodes(), theElem->end_nodes() );
1104     const std::vector<int>& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType );
1105     if ( interlace.empty() )
1106     {
1107       std::reverse( nodes.begin(), nodes.end() ); // polygon
1108     }
1109     else if ( interlace.size() > 1 )
1110     {
1111       SMDS_MeshCell::applyInterlace( interlace, nodes );
1112     }
1113     return GetMeshDS()->ChangeElementNodes( theElem, &nodes[0], nodes.size() );
1114   }
1115   return false;
1116 }
1117
1118 //================================================================================
1119 /*!
1120  * \brief Reorient faces.
1121  * \param theFaces - the faces to reorient. If empty the whole mesh is meant
1122  * \param theDirection - desired direction of normal of \a theFace
1123  * \param theFace - one of \a theFaces that sould be oriented according to
1124  *        \a theDirection and whose orientation defines orientation of other faces
1125  * \return number of reoriented faces.
1126  */
1127 //================================================================================
1128
1129 int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
1130                                   const gp_Dir&            theDirection,
1131                                   const SMDS_MeshElement * theFace)
1132 {
1133   int nbReori = 0;
1134   if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori;
1135
1136   if ( theFaces.empty() )
1137   {
1138     SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true);
1139     while ( fIt->more() )
1140       theFaces.insert( theFaces.end(), fIt->next() );
1141   }
1142
1143   // orient theFace according to theDirection
1144   gp_XYZ normal;
1145   SMESH_MeshAlgos::FaceNormal( theFace, normal, /*normalized=*/false );
1146   if ( normal * theDirection.XYZ() < 0 )
1147     nbReori += Reorient( theFace );
1148
1149   // Orient other faces
1150
1151   set< const SMDS_MeshElement* > startFaces, visitedFaces;
1152   TIDSortedElemSet avoidSet;
1153   set< SMESH_TLink > checkedLinks;
1154   pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
1155
1156   if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
1157     theFaces.erase( theFace );
1158   startFaces.insert( theFace );
1159
1160   int nodeInd1, nodeInd2;
1161   const SMDS_MeshElement*           otherFace;
1162   vector< const SMDS_MeshElement* > facesNearLink;
1163   vector< std::pair< int, int > >   nodeIndsOfFace;
1164
1165   set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
1166   while ( !startFaces.empty() )
1167   {
1168     startFace = startFaces.begin();
1169     theFace = *startFace;
1170     startFaces.erase( startFace );
1171     if ( !visitedFaces.insert( theFace ).second )
1172       continue;
1173
1174     avoidSet.clear();
1175     avoidSet.insert(theFace);
1176
1177     NLink link( theFace->GetNode( 0 ), 0 );
1178
1179     const int nbNodes = theFace->NbCornerNodes();
1180     for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
1181     {
1182       link.second = theFace->GetNode(( i+1 ) % nbNodes );
1183       linkIt_isNew = checkedLinks.insert( link );
1184       if ( !linkIt_isNew.second )
1185       {
1186         // link has already been checked and won't be encountered more
1187         // if the group (theFaces) is manifold
1188         //checkedLinks.erase( linkIt_isNew.first );
1189       }
1190       else
1191       {
1192         facesNearLink.clear();
1193         nodeIndsOfFace.clear();
1194         while (( otherFace = SMESH_MeshAlgos::FindFaceInSet( link.first, link.second,
1195                                                              theFaces, avoidSet,
1196                                                              &nodeInd1, &nodeInd2 )))
1197           if ( otherFace != theFace)
1198           {
1199             facesNearLink.push_back( otherFace );
1200             nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 ));
1201             avoidSet.insert( otherFace );
1202           }
1203         if ( facesNearLink.size() > 1 )
1204         {
1205           // NON-MANIFOLD mesh shell !
1206           // select a face most co-directed with theFace,
1207           // other faces won't be visited this time
1208           gp_XYZ NF, NOF;
1209           SMESH_MeshAlgos::FaceNormal( theFace, NF, /*normalized=*/false );
1210           double proj, maxProj = -1;
1211           for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
1212             SMESH_MeshAlgos::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
1213             if (( proj = Abs( NF * NOF )) > maxProj ) {
1214               maxProj = proj;
1215               otherFace = facesNearLink[i];
1216               nodeInd1  = nodeIndsOfFace[i].first;
1217               nodeInd2  = nodeIndsOfFace[i].second;
1218             }
1219           }
1220           // not to visit rejected faces
1221           for ( size_t i = 0; i < facesNearLink.size(); ++i )
1222             if ( facesNearLink[i] != otherFace && theFaces.size() > 1 )
1223               visitedFaces.insert( facesNearLink[i] );
1224         }
1225         else if ( facesNearLink.size() == 1 )
1226         {
1227           otherFace = facesNearLink[0];
1228           nodeInd1  = nodeIndsOfFace.back().first;
1229           nodeInd2  = nodeIndsOfFace.back().second;
1230         }
1231         if ( otherFace && otherFace != theFace)
1232         {
1233           // link must be reverse in otherFace if orientation ot otherFace
1234           // is same as that of theFace
1235           if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
1236           {
1237             nbReori += Reorient( otherFace );
1238           }
1239           startFaces.insert( otherFace );
1240         }
1241       }
1242       std::swap( link.first, link.second ); // reverse the link
1243     }
1244   }
1245   return nbReori;
1246 }
1247
1248 //=======================================================================
1249 //function : getBadRate
1250 //purpose  :
1251 //=======================================================================
1252
1253 static double getBadRate (const SMDS_MeshElement*               theElem,
1254                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1255 {
1256   SMESH::Controls::TSequenceOfXYZ P;
1257   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1258     return 1e100;
1259   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1260   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1261 }
1262
1263 //=======================================================================
1264 //function : QuadToTri
1265 //purpose  : Cut quadrangles into triangles.
1266 //           theCrit is used to select a diagonal to cut
1267 //=======================================================================
1268
1269 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1270                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1271 {
1272   myLastCreatedElems.Clear();
1273   myLastCreatedNodes.Clear();
1274
1275   if ( !theCrit.get() )
1276     return false;
1277
1278   SMESHDS_Mesh * aMesh = GetMeshDS();
1279
1280   Handle(Geom_Surface) surface;
1281   SMESH_MesherHelper   helper( *GetMesh() );
1282
1283   TIDSortedElemSet::iterator itElem;
1284   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
1285   {
1286     const SMDS_MeshElement* elem = *itElem;
1287     if ( !elem || elem->GetType() != SMDSAbs_Face )
1288       continue;
1289     if ( elem->NbCornerNodes() != 4 )
1290       continue;
1291
1292     // retrieve element nodes
1293     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1294
1295     // compare two sets of possible triangles
1296     double aBadRate1, aBadRate2; // to what extent a set is bad
1297     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1298     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1299     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1300
1301     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1302     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1303     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1304
1305     const int aShapeId = FindShape( elem );
1306     const SMDS_MeshElement* newElem1 = 0;
1307     const SMDS_MeshElement* newElem2 = 0;
1308
1309     if ( !elem->IsQuadratic() ) // split liner quadrangle
1310     {
1311       // for MaxElementLength2D functor we return minimum diagonal for splitting,
1312       // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1313       if ( aBadRate1 <= aBadRate2 ) {
1314         // tr1 + tr2 is better
1315         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1316         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1317       }
1318       else {
1319         // tr3 + tr4 is better
1320         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1321         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1322       }
1323     }
1324     else // split quadratic quadrangle
1325     {
1326       helper.SetIsQuadratic( true );
1327       helper.SetIsBiQuadratic( aNodes.size() == 9 );
1328
1329       helper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem ));
1330       if ( aNodes.size() == 9 )
1331       {
1332         helper.SetIsBiQuadratic( true );
1333         if ( aBadRate1 <= aBadRate2 )
1334           helper.AddTLinkNode( aNodes[0], aNodes[2], aNodes[8] );
1335         else
1336           helper.AddTLinkNode( aNodes[1], aNodes[3], aNodes[8] );
1337       }
1338       // create a new element
1339       if ( aBadRate1 <= aBadRate2 ) {
1340         newElem1 = helper.AddFace( aNodes[2], aNodes[3], aNodes[0] );
1341         newElem2 = helper.AddFace( aNodes[2], aNodes[0], aNodes[1] );
1342       }
1343       else {
1344         newElem1 = helper.AddFace( aNodes[3], aNodes[0], aNodes[1] );
1345         newElem2 = helper.AddFace( aNodes[3], aNodes[1], aNodes[2] );
1346       }
1347     } // quadratic case
1348
1349     // care of a new element
1350
1351     myLastCreatedElems.Append(newElem1);
1352     myLastCreatedElems.Append(newElem2);
1353     AddToSameGroups( newElem1, elem, aMesh );
1354     AddToSameGroups( newElem2, elem, aMesh );
1355
1356     // put a new triangle on the same shape
1357     if ( aShapeId )
1358       aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1359     aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1360
1361     aMesh->RemoveElement( elem );
1362   }
1363   return true;
1364 }
1365
1366 //=======================================================================
1367 /*!
1368  * \brief Split each of given quadrangles into 4 triangles.
1369  * \param theElems - The faces to be splitted. If empty all faces are split.
1370  */
1371 //=======================================================================
1372
1373 void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
1374 {
1375   myLastCreatedElems.Clear();
1376   myLastCreatedNodes.Clear();
1377
1378   SMESH_MesherHelper helper( *GetMesh() );
1379   helper.SetElementsOnShape( true );
1380
1381   SMDS_ElemIteratorPtr faceIt;
1382   if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face);
1383   else                    faceIt = elemSetIterator( theElems );
1384
1385   bool   checkUV;
1386   gp_XY  uv [9]; uv[8] = gp_XY(0,0);
1387   gp_XYZ xyz[9];
1388   vector< const SMDS_MeshNode* > nodes;
1389   SMESHDS_SubMesh*               subMeshDS;
1390   TopoDS_Face                    F;
1391   Handle(Geom_Surface)           surface;
1392   TopLoc_Location                loc;
1393
1394   while ( faceIt->more() )
1395   {
1396     const SMDS_MeshElement* quad = faceIt->next();
1397     if ( !quad || quad->NbCornerNodes() != 4 )
1398       continue;
1399
1400     // get a surface the quad is on
1401
1402     if ( quad->getshapeId() < 1 )
1403     {
1404       F.Nullify();
1405       helper.SetSubShape( 0 );
1406       subMeshDS = 0;
1407     }
1408     else if ( quad->getshapeId() != helper.GetSubShapeID() )
1409     {
1410       helper.SetSubShape( quad->getshapeId() );
1411       if ( !helper.GetSubShape().IsNull() &&
1412            helper.GetSubShape().ShapeType() == TopAbs_FACE )
1413       {
1414         F = TopoDS::Face( helper.GetSubShape() );
1415         surface = BRep_Tool::Surface( F, loc );
1416         subMeshDS = GetMeshDS()->MeshElements( quad->getshapeId() );
1417       }
1418       else
1419       {
1420         helper.SetSubShape( 0 );
1421         subMeshDS = 0;
1422       }
1423     }
1424
1425     // create a central node
1426
1427     const SMDS_MeshNode* nCentral;
1428     nodes.assign( quad->begin_nodes(), quad->end_nodes() );
1429
1430     if ( nodes.size() == 9 )
1431     {
1432       nCentral = nodes.back();
1433     }
1434     else
1435     {
1436       size_t iN = 0;
1437       if ( F.IsNull() )
1438       {
1439         for ( ; iN < nodes.size(); ++iN )
1440           xyz[ iN ] = SMESH_TNodeXYZ( nodes[ iN ] );
1441
1442         for ( ; iN < 8; ++iN ) // mid-side points of a linear qudrangle
1443           xyz[ iN ] = 0.5 * ( xyz[ iN - 4 ] + xyz[( iN - 3 )%4 ] );
1444
1445         xyz[ 8 ] = helper.calcTFI( 0.5, 0.5,
1446                                    xyz[0], xyz[1], xyz[2], xyz[3],
1447                                    xyz[4], xyz[5], xyz[6], xyz[7] );
1448       }
1449       else
1450       {
1451         for ( ; iN < nodes.size(); ++iN )
1452           uv[ iN ] = helper.GetNodeUV( F, nodes[iN], nodes[(iN+2)%4], &checkUV );
1453
1454         for ( ; iN < 8; ++iN ) // UV of mid-side points of a linear qudrangle
1455           uv[ iN ] = helper.GetMiddleUV( surface, uv[ iN - 4 ], uv[( iN - 3 )%4 ] );
1456
1457         uv[ 8 ] = helper.calcTFI( 0.5, 0.5,
1458                                   uv[0], uv[1], uv[2], uv[3],
1459                                   uv[4], uv[5], uv[6], uv[7] );
1460
1461         gp_Pnt p = surface->Value( uv[8].X(), uv[8].Y() ).Transformed( loc );
1462         xyz[ 8 ] = p.XYZ();
1463       }
1464
1465       nCentral = helper.AddNode( xyz[8].X(), xyz[8].Y(), xyz[8].Z(), /*id=*/0,
1466                                  uv[8].X(), uv[8].Y() );
1467       myLastCreatedNodes.Append( nCentral );
1468     }
1469
1470     // create 4 triangles
1471
1472     GetMeshDS()->RemoveFreeElement( quad, subMeshDS, /*fromGroups=*/false );
1473     
1474     helper.SetIsQuadratic  ( nodes.size() > 4 );
1475     helper.SetIsBiQuadratic( nodes.size() == 9 );
1476     if ( helper.GetIsQuadratic() )
1477       helper.AddTLinks( static_cast< const SMDS_MeshFace*>( quad ));
1478
1479     for ( int i = 0; i < 4; ++i )
1480     {
1481       SMDS_MeshElement* tria = helper.AddFace( nodes[ i ],
1482                                                nodes[(i+1)%4],
1483                                                nCentral );
1484       ReplaceElemInGroups( tria, quad, GetMeshDS() );
1485       myLastCreatedElems.Append( tria );
1486     }
1487   }
1488 }
1489
1490 //=======================================================================
1491 //function : BestSplit
1492 //purpose  : Find better diagonal for cutting.
1493 //=======================================================================
1494
1495 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1496                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1497 {
1498   myLastCreatedElems.Clear();
1499   myLastCreatedNodes.Clear();
1500
1501   if (!theCrit.get())
1502     return -1;
1503
1504   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1505     return -1;
1506
1507   if( theQuad->NbNodes()==4 ||
1508       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1509
1510     // retrieve element nodes
1511     const SMDS_MeshNode* aNodes [4];
1512     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1513     int i = 0;
1514     //while (itN->more())
1515     while (i<4) {
1516       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1517     }
1518     // compare two sets of possible triangles
1519     double aBadRate1, aBadRate2; // to what extent a set is bad
1520     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1521     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1522     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1523
1524     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1525     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1526     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1527     // for MaxElementLength2D functor we return minimum diagonal for splitting,
1528     // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1529     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1530       return 1; // diagonal 1-3
1531
1532     return 2; // diagonal 2-4
1533   }
1534   return -1;
1535 }
1536
1537 namespace
1538 {
1539   // Methods of splitting volumes into tetra
1540
1541   const int theHexTo5_1[5*4+1] =
1542     {
1543       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1544     };
1545   const int theHexTo5_2[5*4+1] =
1546     {
1547       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1548     };
1549   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1550
1551   const int theHexTo6_1[6*4+1] =
1552     {
1553       1, 5, 6, 0,    0, 1, 2, 6,     0, 4, 5, 6,    0, 4, 6, 7,     0, 2, 3, 6,   0, 3, 7, 6,  -1
1554     };
1555   const int theHexTo6_2[6*4+1] =
1556     {
1557       2, 6, 7, 1,    1, 2, 3, 7,     1, 5, 6, 7,    1, 5, 7, 4,     1, 3, 0, 7,   1, 0, 4, 7,  -1
1558     };
1559   const int theHexTo6_3[6*4+1] =
1560     {
1561       3, 7, 4, 2,    2, 3, 0, 4,     2, 6, 7, 4,    2, 6, 4, 5,     2, 0, 1, 4,   2, 1, 5, 4,  -1
1562     };
1563   const int theHexTo6_4[6*4+1] =
1564     {
1565       0, 4, 5, 3,    3, 0, 1, 5,     3, 7, 4, 5,    3, 7, 5, 6,     3, 1, 2, 5,   3, 2, 6, 5,  -1
1566     };
1567   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1568
1569   const int thePyraTo2_1[2*4+1] =
1570     {
1571       0, 1, 2, 4,    0, 2, 3, 4,   -1
1572     };
1573   const int thePyraTo2_2[2*4+1] =
1574     {
1575       1, 2, 3, 4,    1, 3, 0, 4,   -1
1576     };
1577   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1578
1579   const int thePentaTo3_1[3*4+1] =
1580     {
1581       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1582     };
1583   const int thePentaTo3_2[3*4+1] =
1584     {
1585       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1586     };
1587   const int thePentaTo3_3[3*4+1] =
1588     {
1589       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1590     };
1591   const int thePentaTo3_4[3*4+1] =
1592     {
1593       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1594     };
1595   const int thePentaTo3_5[3*4+1] =
1596     {
1597       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1598     };
1599   const int thePentaTo3_6[3*4+1] =
1600     {
1601       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1602     };
1603   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1604                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1605
1606   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1607   {
1608     int _n1, _n2, _n3;
1609     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1610     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1611     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1612   };
1613   struct TSplitMethod
1614   {
1615     int        _nbTetra;
1616     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1617     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1618     bool       _ownConn;      //!< to delete _connectivity in destructor
1619     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1620
1621     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1622       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1623     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1624     bool hasFacet( const TTriangleFacet& facet ) const
1625     {
1626       const int* tetConn = _connectivity;
1627       for ( ; tetConn[0] >= 0; tetConn += 4 )
1628         if (( facet.contains( tetConn[0] ) +
1629               facet.contains( tetConn[1] ) +
1630               facet.contains( tetConn[2] ) +
1631               facet.contains( tetConn[3] )) == 3 )
1632           return true;
1633       return false;
1634     }
1635   };
1636
1637   //=======================================================================
1638   /*!
1639    * \brief return TSplitMethod for the given element
1640    */
1641   //=======================================================================
1642
1643   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1644   {
1645     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1646
1647     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1648     // an edge and a face barycenter; tertaherdons are based on triangles and
1649     // a volume barycenter
1650     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1651
1652     // Find out how adjacent volumes are split
1653
1654     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1655     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1656     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1657     {
1658       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1659       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1660       if ( nbNodes < 4 ) continue;
1661
1662       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1663       const int* nInd = vol.GetFaceNodesIndices( iF );
1664       if ( nbNodes == 4 )
1665       {
1666         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1667         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1668         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1669         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1670       }
1671       else
1672       {
1673         int iCom = 0; // common node of triangle faces to split into
1674         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1675         {
1676           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1677                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1678                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1679           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1680                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1681                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1682           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1683           {
1684             triaSplits.push_back( t012 );
1685             triaSplits.push_back( t023 );
1686             break;
1687           }
1688         }
1689       }
1690       if ( !triaSplits.empty() )
1691         hasAdjacentSplits = true;
1692     }
1693
1694     // Among variants of split method select one compliant with adjacent volumes
1695
1696     TSplitMethod method;
1697     if ( !vol.Element()->IsPoly() && !is24TetMode )
1698     {
1699       int nbVariants = 2, nbTet = 0;
1700       const int** connVariants = 0;
1701       switch ( vol.Element()->GetEntityType() )
1702       {
1703       case SMDSEntity_Hexa:
1704       case SMDSEntity_Quad_Hexa:
1705       case SMDSEntity_TriQuad_Hexa:
1706         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1707           connVariants = theHexTo5, nbTet = 5;
1708         else
1709           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1710         break;
1711       case SMDSEntity_Pyramid:
1712       case SMDSEntity_Quad_Pyramid:
1713         connVariants = thePyraTo2;  nbTet = 2;
1714         break;
1715       case SMDSEntity_Penta:
1716       case SMDSEntity_Quad_Penta:
1717         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1718         break;
1719       default:
1720         nbVariants = 0;
1721       }
1722       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1723       {
1724         // check method compliancy with adjacent tetras,
1725         // all found splits must be among facets of tetras described by this method
1726         method = TSplitMethod( nbTet, connVariants[variant] );
1727         if ( hasAdjacentSplits && method._nbTetra > 0 )
1728         {
1729           bool facetCreated = true;
1730           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1731           {
1732             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1733             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1734               facetCreated = method.hasFacet( *facet );
1735           }
1736           if ( !facetCreated )
1737             method = TSplitMethod(0); // incompatible method
1738         }
1739       }
1740     }
1741     if ( method._nbTetra < 1 )
1742     {
1743       // No standard method is applicable, use a generic solution:
1744       // each facet of a volume is split into triangles and
1745       // each of triangles and a volume barycenter form a tetrahedron.
1746
1747       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1748
1749       int* connectivity = new int[ maxTetConnSize + 1 ];
1750       method._connectivity = connectivity;
1751       method._ownConn = true;
1752       method._baryNode = !isHex27; // to create central node or not
1753
1754       int connSize = 0;
1755       int baryCenInd = vol.NbNodes() - int( isHex27 );
1756       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1757       {
1758         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1759         const int*   nInd = vol.GetFaceNodesIndices( iF );
1760         // find common node of triangle facets of tetra to create
1761         int iCommon = 0; // index in linear numeration
1762         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1763         if ( !triaSplits.empty() )
1764         {
1765           // by found facets
1766           const TTriangleFacet* facet = &triaSplits.front();
1767           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1768             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1769                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1770               break;
1771         }
1772         else if ( nbNodes > 3 && !is24TetMode )
1773         {
1774           // find the best method of splitting into triangles by aspect ratio
1775           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1776           map< double, int > badness2iCommon;
1777           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1778           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1779           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1780           {
1781             double badness = 0;
1782             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1783             {
1784               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1785                                       nodes[ iQ*((iLast-1)%nbNodes)],
1786                                       nodes[ iQ*((iLast  )%nbNodes)]);
1787               badness += getBadRate( &tria, aspectRatio );
1788             }
1789             badness2iCommon.insert( make_pair( badness, iCommon ));
1790           }
1791           // use iCommon with lowest badness
1792           iCommon = badness2iCommon.begin()->second;
1793         }
1794         if ( iCommon >= nbNodes )
1795           iCommon = 0; // something wrong
1796
1797         // fill connectivity of tetrahedra based on a current face
1798         int nbTet = nbNodes - 2;
1799         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1800         {
1801           int faceBaryCenInd;
1802           if ( isHex27 )
1803           {
1804             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
1805             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
1806           }
1807           else
1808           {
1809             method._faceBaryNode[ iF ] = 0;
1810             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1811           }
1812           nbTet = nbNodes;
1813           for ( int i = 0; i < nbTet; ++i )
1814           {
1815             int i1 = i, i2 = (i+1) % nbNodes;
1816             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1817             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1818             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1819             connectivity[ connSize++ ] = faceBaryCenInd;
1820             connectivity[ connSize++ ] = baryCenInd;
1821           }
1822         }
1823         else
1824         {
1825           for ( int i = 0; i < nbTet; ++i )
1826           {
1827             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1828             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1829             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1830             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1831             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1832             connectivity[ connSize++ ] = baryCenInd;
1833           }
1834         }
1835         method._nbTetra += nbTet;
1836
1837       } // loop on volume faces
1838
1839       connectivity[ connSize++ ] = -1;
1840
1841     } // end of generic solution
1842
1843     return method;
1844   }
1845   //================================================================================
1846   /*!
1847    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1848    */
1849   //================================================================================
1850
1851   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1852   {
1853     // find the tetrahedron including the three nodes of facet
1854     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1855     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1856     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1857     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1858     while ( volIt1->more() )
1859     {
1860       const SMDS_MeshElement* v = volIt1->next();
1861       SMDSAbs_EntityType type = v->GetEntityType();
1862       if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
1863         continue;
1864       if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
1865         continue; // medium node not allowed
1866       const int ind2 = v->GetNodeIndex( n2 );
1867       if ( ind2 < 0 || 3 < ind2 )
1868         continue;
1869       const int ind3 = v->GetNodeIndex( n3 );
1870       if ( ind3 < 0 || 3 < ind3 )
1871         continue;
1872       return true;
1873     }
1874     return false;
1875   }
1876
1877   //=======================================================================
1878   /*!
1879    * \brief A key of a face of volume
1880    */
1881   //=======================================================================
1882
1883   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
1884   {
1885     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1886     {
1887       TIDSortedNodeSet sortedNodes;
1888       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1889       int nbNodes = vol.NbFaceNodes( iF );
1890       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1891       for ( int i = 0; i < nbNodes; i += iQ )
1892         sortedNodes.insert( fNodes[i] );
1893       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1894       first.first   = (*(n++))->GetID();
1895       first.second  = (*(n++))->GetID();
1896       second.first  = (*(n++))->GetID();
1897       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
1898     }
1899   };
1900 } // namespace
1901
1902 //=======================================================================
1903 //function : SplitVolumesIntoTetra
1904 //purpose  : Split volume elements into tetrahedra.
1905 //=======================================================================
1906
1907 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1908                                               const int                theMethodFlags)
1909 {
1910   // std-like iterator on coordinates of nodes of mesh element
1911   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1912   NXyzIterator xyzEnd;
1913
1914   SMDS_VolumeTool    volTool;
1915   SMESH_MesherHelper helper( *GetMesh());
1916
1917   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1918   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1919
1920   SMESH_SequenceOfElemPtr newNodes, newElems;
1921
1922   // map face of volume to it's baricenrtic node
1923   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1924   double bc[3];
1925
1926   TIDSortedElemSet::const_iterator elem = theElems.begin();
1927   for ( ; elem != theElems.end(); ++elem )
1928   {
1929     if ( (*elem)->GetType() != SMDSAbs_Volume )
1930       continue;
1931     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1932     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
1933       continue;
1934
1935     if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
1936
1937     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1938     if ( splitMethod._nbTetra < 1 ) continue;
1939
1940     // find submesh to add new tetras to
1941     if ( !subMesh || !subMesh->Contains( *elem ))
1942     {
1943       int shapeID = FindShape( *elem );
1944       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1945       subMesh = GetMeshDS()->MeshElements( shapeID );
1946     }
1947     int iQ;
1948     if ( (*elem)->IsQuadratic() )
1949     {
1950       iQ = 2;
1951       // add quadratic links to the helper
1952       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1953       {
1954         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1955         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
1956         for ( int iN = 0; iN < nbN; iN += iQ )
1957           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
1958       }
1959       helper.SetIsQuadratic( true );
1960     }
1961     else
1962     {
1963       iQ = 1;
1964       helper.SetIsQuadratic( false );
1965     }
1966     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1967     helper.SetElementsOnShape( true );
1968     if ( splitMethod._baryNode )
1969     {
1970       // make a node at barycenter
1971       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1972       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1973       nodes.push_back( gcNode );
1974       newNodes.Append( gcNode );
1975     }
1976     if ( !splitMethod._faceBaryNode.empty() )
1977     {
1978       // make or find baricentric nodes of faces
1979       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1980       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1981       {
1982         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1983           volFace2BaryNode.insert
1984           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
1985         if ( !f_n->second )
1986         {
1987           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1988           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1989         }
1990         nodes.push_back( iF_n->second = f_n->second );
1991       }
1992     }
1993
1994     // make tetras
1995     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1996     const int* tetConn = splitMethod._connectivity;
1997     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1998       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1999                                                        nodes[ tetConn[1] ],
2000                                                        nodes[ tetConn[2] ],
2001                                                        nodes[ tetConn[3] ]));
2002
2003     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
2004
2005     // Split faces on sides of the split volume
2006
2007     const SMDS_MeshNode** volNodes = volTool.GetNodes();
2008     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
2009     {
2010       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
2011       if ( nbNodes < 4 ) continue;
2012
2013       // find an existing face
2014       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
2015                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
2016       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
2017                                                                        /*noMedium=*/false))
2018       {
2019         // make triangles
2020         helper.SetElementsOnShape( false );
2021         vector< const SMDS_MeshElement* > triangles;
2022
2023         // find submesh to add new triangles in
2024         if ( !fSubMesh || !fSubMesh->Contains( face ))
2025         {
2026           int shapeID = FindShape( face );
2027           fSubMesh = GetMeshDS()->MeshElements( shapeID );
2028         }
2029         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
2030         if ( iF_n != splitMethod._faceBaryNode.end() )
2031         {
2032           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
2033           {
2034             const SMDS_MeshNode* n1 = fNodes[iN];
2035             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
2036             const SMDS_MeshNode *n3 = iF_n->second;
2037             if ( !volTool.IsFaceExternal( iF ))
2038               swap( n2, n3 );
2039             triangles.push_back( helper.AddFace( n1,n2,n3 ));
2040
2041             if ( fSubMesh && n3->getshapeId() < 1 )
2042               fSubMesh->AddNode( n3 );
2043           }
2044         }
2045         else
2046         {
2047           // among possible triangles create ones discribed by split method
2048           const int* nInd = volTool.GetFaceNodesIndices( iF );
2049           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
2050           int iCom = 0; // common node of triangle faces to split into
2051           list< TTriangleFacet > facets;
2052           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
2053           {
2054             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
2055                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
2056                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
2057             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
2058                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
2059                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
2060             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
2061             {
2062               facets.push_back( t012 );
2063               facets.push_back( t023 );
2064               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
2065                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
2066                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
2067                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
2068               break;
2069             }
2070           }
2071           list< TTriangleFacet >::iterator facet = facets.begin();
2072           for ( ; facet != facets.end(); ++facet )
2073           {
2074             if ( !volTool.IsFaceExternal( iF ))
2075               swap( facet->_n2, facet->_n3 );
2076             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
2077                                                  volNodes[ facet->_n2 ],
2078                                                  volNodes[ facet->_n3 ]));
2079           }
2080         }
2081         for ( int i = 0; i < triangles.size(); ++i )
2082         {
2083           if ( !triangles[i] ) continue;
2084           if ( fSubMesh )
2085             fSubMesh->AddElement( triangles[i]);
2086           newElems.Append( triangles[i] );
2087         }
2088         ReplaceElemInGroups( face, triangles, GetMeshDS() );
2089         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
2090       }
2091
2092     } // loop on volume faces to split them into triangles
2093
2094     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
2095
2096     if ( geomType == SMDSEntity_TriQuad_Hexa )
2097     {
2098       // remove medium nodes that could become free
2099       for ( int i = 20; i < volTool.NbNodes(); ++i )
2100         if ( volNodes[i]->NbInverseElements() == 0 )
2101           GetMeshDS()->RemoveNode( volNodes[i] );
2102     }
2103   } // loop on volumes to split
2104
2105   myLastCreatedNodes = newNodes;
2106   myLastCreatedElems = newElems;
2107 }
2108
2109 //=======================================================================
2110 //function : AddToSameGroups
2111 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
2112 //=======================================================================
2113
2114 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
2115                                         const SMDS_MeshElement* elemInGroups,
2116                                         SMESHDS_Mesh *          aMesh)
2117 {
2118   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2119   if (!groups.empty()) {
2120     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2121     for ( ; grIt != groups.end(); grIt++ ) {
2122       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2123       if ( group && group->Contains( elemInGroups ))
2124         group->SMDSGroup().Add( elemToAdd );
2125     }
2126   }
2127 }
2128
2129
2130 //=======================================================================
2131 //function : RemoveElemFromGroups
2132 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
2133 //=======================================================================
2134 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
2135                                              SMESHDS_Mesh *          aMesh)
2136 {
2137   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2138   if (!groups.empty())
2139   {
2140     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
2141     for (; GrIt != groups.end(); GrIt++)
2142     {
2143       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
2144       if (!grp || grp->IsEmpty()) continue;
2145       grp->SMDSGroup().Remove(removeelem);
2146     }
2147   }
2148 }
2149
2150 //================================================================================
2151 /*!
2152  * \brief Replace elemToRm by elemToAdd in the all groups
2153  */
2154 //================================================================================
2155
2156 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
2157                                             const SMDS_MeshElement* elemToAdd,
2158                                             SMESHDS_Mesh *          aMesh)
2159 {
2160   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2161   if (!groups.empty()) {
2162     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2163     for ( ; grIt != groups.end(); grIt++ ) {
2164       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2165       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
2166         group->SMDSGroup().Add( elemToAdd );
2167     }
2168   }
2169 }
2170
2171 //================================================================================
2172 /*!
2173  * \brief Replace elemToRm by elemToAdd in the all groups
2174  */
2175 //================================================================================
2176
2177 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
2178                                             const vector<const SMDS_MeshElement*>& elemToAdd,
2179                                             SMESHDS_Mesh *                         aMesh)
2180 {
2181   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2182   if (!groups.empty())
2183   {
2184     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2185     for ( ; grIt != groups.end(); grIt++ ) {
2186       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2187       if ( group && group->SMDSGroup().Remove( elemToRm ) )
2188         for ( int i = 0; i < elemToAdd.size(); ++i )
2189           group->SMDSGroup().Add( elemToAdd[ i ] );
2190     }
2191   }
2192 }
2193
2194 //=======================================================================
2195 //function : QuadToTri
2196 //purpose  : Cut quadrangles into triangles.
2197 //           theCrit is used to select a diagonal to cut
2198 //=======================================================================
2199
2200 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
2201                                   const bool         the13Diag)
2202 {
2203   myLastCreatedElems.Clear();
2204   myLastCreatedNodes.Clear();
2205
2206   MESSAGE( "::QuadToTri()" );
2207
2208   SMESHDS_Mesh * aMesh = GetMeshDS();
2209
2210   Handle(Geom_Surface) surface;
2211   SMESH_MesherHelper   helper( *GetMesh() );
2212
2213   TIDSortedElemSet::iterator itElem;
2214   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2215     const SMDS_MeshElement* elem = *itElem;
2216     if ( !elem || elem->GetType() != SMDSAbs_Face )
2217       continue;
2218     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
2219     if(!isquad) continue;
2220
2221     if(elem->NbNodes()==4) {
2222       // retrieve element nodes
2223       const SMDS_MeshNode* aNodes [4];
2224       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2225       int i = 0;
2226       while ( itN->more() )
2227         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2228
2229       int aShapeId = FindShape( elem );
2230       const SMDS_MeshElement* newElem1 = 0;
2231       const SMDS_MeshElement* newElem2 = 0;
2232       if ( the13Diag ) {
2233         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
2234         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
2235       }
2236       else {
2237         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
2238         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
2239       }
2240       myLastCreatedElems.Append(newElem1);
2241       myLastCreatedElems.Append(newElem2);
2242       // put a new triangle on the same shape and add to the same groups
2243       if ( aShapeId )
2244         {
2245           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2246           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2247         }
2248       AddToSameGroups( newElem1, elem, aMesh );
2249       AddToSameGroups( newElem2, elem, aMesh );
2250       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
2251       aMesh->RemoveElement( elem );
2252     }
2253
2254     // Quadratic quadrangle
2255
2256     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
2257
2258       // get surface elem is on
2259       int aShapeId = FindShape( elem );
2260       if ( aShapeId != helper.GetSubShapeID() ) {
2261         surface.Nullify();
2262         TopoDS_Shape shape;
2263         if ( aShapeId > 0 )
2264           shape = aMesh->IndexToShape( aShapeId );
2265         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
2266           TopoDS_Face face = TopoDS::Face( shape );
2267           surface = BRep_Tool::Surface( face );
2268           if ( !surface.IsNull() )
2269             helper.SetSubShape( shape );
2270         }
2271       }
2272
2273       const SMDS_MeshNode* aNodes [8];
2274       const SMDS_MeshNode* inFaceNode = 0;
2275       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2276       int i = 0;
2277       while ( itN->more() ) {
2278         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2279         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
2280              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
2281         {
2282           inFaceNode = aNodes[ i-1 ];
2283         }
2284       }
2285
2286       // find middle point for (0,1,2,3)
2287       // and create a node in this point;
2288       gp_XYZ p( 0,0,0 );
2289       if ( surface.IsNull() ) {
2290         for(i=0; i<4; i++)
2291           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
2292         p /= 4;
2293       }
2294       else {
2295         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
2296         gp_XY uv( 0,0 );
2297         for(i=0; i<4; i++)
2298           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
2299         uv /= 4.;
2300         p = surface->Value( uv.X(), uv.Y() ).XYZ();
2301       }
2302       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
2303       myLastCreatedNodes.Append(newN);
2304
2305       // create a new element
2306       const SMDS_MeshElement* newElem1 = 0;
2307       const SMDS_MeshElement* newElem2 = 0;
2308       if ( the13Diag ) {
2309         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
2310                                   aNodes[6], aNodes[7], newN );
2311         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
2312                                   newN,      aNodes[4], aNodes[5] );
2313       }
2314       else {
2315         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
2316                                   aNodes[7], aNodes[4], newN );
2317         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
2318                                   newN,      aNodes[5], aNodes[6] );
2319       }
2320       myLastCreatedElems.Append(newElem1);
2321       myLastCreatedElems.Append(newElem2);
2322       // put a new triangle on the same shape and add to the same groups
2323       if ( aShapeId )
2324         {
2325           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2326           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2327         }
2328       AddToSameGroups( newElem1, elem, aMesh );
2329       AddToSameGroups( newElem2, elem, aMesh );
2330       aMesh->RemoveElement( elem );
2331     }
2332   }
2333
2334   return true;
2335 }
2336
2337 //=======================================================================
2338 //function : getAngle
2339 //purpose  :
2340 //=======================================================================
2341
2342 double getAngle(const SMDS_MeshElement * tr1,
2343                 const SMDS_MeshElement * tr2,
2344                 const SMDS_MeshNode *    n1,
2345                 const SMDS_MeshNode *    n2)
2346 {
2347   double angle = 2. * M_PI; // bad angle
2348
2349   // get normals
2350   SMESH::Controls::TSequenceOfXYZ P1, P2;
2351   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2352        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2353     return angle;
2354   gp_Vec N1,N2;
2355   if(!tr1->IsQuadratic())
2356     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2357   else
2358     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2359   if ( N1.SquareMagnitude() <= gp::Resolution() )
2360     return angle;
2361   if(!tr2->IsQuadratic())
2362     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2363   else
2364     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2365   if ( N2.SquareMagnitude() <= gp::Resolution() )
2366     return angle;
2367
2368   // find the first diagonal node n1 in the triangles:
2369   // take in account a diagonal link orientation
2370   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2371   for ( int t = 0; t < 2; t++ ) {
2372     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2373     int i = 0, iDiag = -1;
2374     while ( it->more()) {
2375       const SMDS_MeshElement *n = it->next();
2376       if ( n == n1 || n == n2 ) {
2377         if ( iDiag < 0)
2378           iDiag = i;
2379         else {
2380           if ( i - iDiag == 1 )
2381             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2382           else
2383             nFirst[ t ] = n;
2384           break;
2385         }
2386       }
2387       i++;
2388     }
2389   }
2390   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2391     N2.Reverse();
2392
2393   angle = N1.Angle( N2 );
2394   //SCRUTE( angle );
2395   return angle;
2396 }
2397
2398 // =================================================
2399 // class generating a unique ID for a pair of nodes
2400 // and able to return nodes by that ID
2401 // =================================================
2402 class LinkID_Gen {
2403 public:
2404
2405   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2406     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2407   {}
2408
2409   long GetLinkID (const SMDS_MeshNode * n1,
2410                   const SMDS_MeshNode * n2) const
2411   {
2412     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2413   }
2414
2415   bool GetNodes (const long             theLinkID,
2416                  const SMDS_MeshNode* & theNode1,
2417                  const SMDS_MeshNode* & theNode2) const
2418   {
2419     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2420     if ( !theNode1 ) return false;
2421     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2422     if ( !theNode2 ) return false;
2423     return true;
2424   }
2425
2426 private:
2427   LinkID_Gen();
2428   const SMESHDS_Mesh* myMesh;
2429   long                myMaxID;
2430 };
2431
2432
2433 //=======================================================================
2434 //function : TriToQuad
2435 //purpose  : Fuse neighbour triangles into quadrangles.
2436 //           theCrit is used to select a neighbour to fuse with.
2437 //           theMaxAngle is a max angle between element normals at which
2438 //           fusion is still performed.
2439 //=======================================================================
2440
2441 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2442                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2443                                   const double                         theMaxAngle)
2444 {
2445   myLastCreatedElems.Clear();
2446   myLastCreatedNodes.Clear();
2447
2448   MESSAGE( "::TriToQuad()" );
2449
2450   if ( !theCrit.get() )
2451     return false;
2452
2453   SMESHDS_Mesh * aMesh = GetMeshDS();
2454
2455   // Prepare data for algo: build
2456   // 1. map of elements with their linkIDs
2457   // 2. map of linkIDs with their elements
2458
2459   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2460   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2461   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2462   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2463
2464   TIDSortedElemSet::iterator itElem;
2465   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
2466   {
2467     const SMDS_MeshElement* elem = *itElem;
2468     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2469     bool IsTria = ( elem->NbCornerNodes()==3 );
2470     if (!IsTria) continue;
2471
2472     // retrieve element nodes
2473     const SMDS_MeshNode* aNodes [4];
2474     SMDS_NodeIteratorPtr itN = elem->nodeIterator();
2475     int i = 0;
2476     while ( i < 3 )
2477       aNodes[ i++ ] = itN->next();
2478     aNodes[ 3 ] = aNodes[ 0 ];
2479
2480     // fill maps
2481     for ( i = 0; i < 3; i++ ) {
2482       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2483       // check if elements sharing a link can be fused
2484       itLE = mapLi_listEl.find( link );
2485       if ( itLE != mapLi_listEl.end() ) {
2486         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2487           continue;
2488         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2489         //if ( FindShape( elem ) != FindShape( elem2 ))
2490         //  continue; // do not fuse triangles laying on different shapes
2491         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2492           continue; // avoid making badly shaped quads
2493         (*itLE).second.push_back( elem );
2494       }
2495       else {
2496         mapLi_listEl[ link ].push_back( elem );
2497       }
2498       mapEl_setLi [ elem ].insert( link );
2499     }
2500   }
2501   // Clean the maps from the links shared by a sole element, ie
2502   // links to which only one element is bound in mapLi_listEl
2503
2504   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2505     int nbElems = (*itLE).second.size();
2506     if ( nbElems < 2  ) {
2507       const SMDS_MeshElement* elem = (*itLE).second.front();
2508       SMESH_TLink link = (*itLE).first;
2509       mapEl_setLi[ elem ].erase( link );
2510       if ( mapEl_setLi[ elem ].empty() )
2511         mapEl_setLi.erase( elem );
2512     }
2513   }
2514
2515   // Algo: fuse triangles into quadrangles
2516
2517   while ( ! mapEl_setLi.empty() ) {
2518     // Look for the start element:
2519     // the element having the least nb of shared links
2520     const SMDS_MeshElement* startElem = 0;
2521     int minNbLinks = 4;
2522     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2523       int nbLinks = (*itEL).second.size();
2524       if ( nbLinks < minNbLinks ) {
2525         startElem = (*itEL).first;
2526         minNbLinks = nbLinks;
2527         if ( minNbLinks == 1 )
2528           break;
2529       }
2530     }
2531
2532     // search elements to fuse starting from startElem or links of elements
2533     // fused earlyer - startLinks
2534     list< SMESH_TLink > startLinks;
2535     while ( startElem || !startLinks.empty() ) {
2536       while ( !startElem && !startLinks.empty() ) {
2537         // Get an element to start, by a link
2538         SMESH_TLink linkId = startLinks.front();
2539         startLinks.pop_front();
2540         itLE = mapLi_listEl.find( linkId );
2541         if ( itLE != mapLi_listEl.end() ) {
2542           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2543           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2544           for ( ; itE != listElem.end() ; itE++ )
2545             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2546               startElem = (*itE);
2547           mapLi_listEl.erase( itLE );
2548         }
2549       }
2550
2551       if ( startElem ) {
2552         // Get candidates to be fused
2553         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2554         const SMESH_TLink *link12, *link13;
2555         startElem = 0;
2556         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2557         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2558         ASSERT( !setLi.empty() );
2559         set< SMESH_TLink >::iterator itLi;
2560         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2561         {
2562           const SMESH_TLink & link = (*itLi);
2563           itLE = mapLi_listEl.find( link );
2564           if ( itLE == mapLi_listEl.end() )
2565             continue;
2566
2567           const SMDS_MeshElement* elem = (*itLE).second.front();
2568           if ( elem == tr1 )
2569             elem = (*itLE).second.back();
2570           mapLi_listEl.erase( itLE );
2571           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2572             continue;
2573           if ( tr2 ) {
2574             tr3 = elem;
2575             link13 = &link;
2576           }
2577           else {
2578             tr2 = elem;
2579             link12 = &link;
2580           }
2581
2582           // add other links of elem to list of links to re-start from
2583           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2584           set< SMESH_TLink >::iterator it;
2585           for ( it = links.begin(); it != links.end(); it++ ) {
2586             const SMESH_TLink& link2 = (*it);
2587             if ( link2 != link )
2588               startLinks.push_back( link2 );
2589           }
2590         }
2591
2592         // Get nodes of possible quadrangles
2593         const SMDS_MeshNode *n12 [4], *n13 [4];
2594         bool Ok12 = false, Ok13 = false;
2595         const SMDS_MeshNode *linkNode1, *linkNode2;
2596         if(tr2) {
2597           linkNode1 = link12->first;
2598           linkNode2 = link12->second;
2599           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2600             Ok12 = true;
2601         }
2602         if(tr3) {
2603           linkNode1 = link13->first;
2604           linkNode2 = link13->second;
2605           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2606             Ok13 = true;
2607         }
2608
2609         // Choose a pair to fuse
2610         if ( Ok12 && Ok13 ) {
2611           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2612           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2613           double aBadRate12 = getBadRate( &quad12, theCrit );
2614           double aBadRate13 = getBadRate( &quad13, theCrit );
2615           if (  aBadRate13 < aBadRate12 )
2616             Ok12 = false;
2617           else
2618             Ok13 = false;
2619         }
2620
2621         // Make quadrangles
2622         // and remove fused elems and remove links from the maps
2623         mapEl_setLi.erase( tr1 );
2624         if ( Ok12 )
2625         {
2626           mapEl_setLi.erase( tr2 );
2627           mapLi_listEl.erase( *link12 );
2628           if ( tr1->NbNodes() == 3 )
2629           {
2630             const SMDS_MeshElement* newElem = 0;
2631             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2632             myLastCreatedElems.Append(newElem);
2633             AddToSameGroups( newElem, tr1, aMesh );
2634             int aShapeId = tr1->getshapeId();
2635             if ( aShapeId )
2636               aMesh->SetMeshElementOnShape( newElem, aShapeId );
2637             aMesh->RemoveElement( tr1 );
2638             aMesh->RemoveElement( tr2 );
2639           }
2640           else {
2641             vector< const SMDS_MeshNode* > N1;
2642             vector< const SMDS_MeshNode* > N2;
2643             getNodesFromTwoTria(tr1,tr2,N1,N2);
2644             // now we receive following N1 and N2 (using numeration as in image in InverseDiag())
2645             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2646             // i.e. first nodes from both arrays form a new diagonal
2647             const SMDS_MeshNode* aNodes[8];
2648             aNodes[0] = N1[0];
2649             aNodes[1] = N1[1];
2650             aNodes[2] = N2[0];
2651             aNodes[3] = N2[1];
2652             aNodes[4] = N1[3];
2653             aNodes[5] = N2[5];
2654             aNodes[6] = N2[3];
2655             aNodes[7] = N1[5];
2656             const SMDS_MeshElement* newElem = 0;
2657             if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
2658               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2659                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
2660             else
2661               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2662                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2663             myLastCreatedElems.Append(newElem);
2664             AddToSameGroups( newElem, tr1, aMesh );
2665             int aShapeId = tr1->getshapeId();
2666             if ( aShapeId )
2667               aMesh->SetMeshElementOnShape( newElem, aShapeId );
2668             aMesh->RemoveElement( tr1 );
2669             aMesh->RemoveElement( tr2 );
2670             // remove middle node (9)
2671             if ( N1[4]->NbInverseElements() == 0 )
2672               aMesh->RemoveNode( N1[4] );
2673             if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
2674               aMesh->RemoveNode( N1[6] );
2675             if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
2676               aMesh->RemoveNode( N2[6] );
2677           }
2678         }
2679         else if ( Ok13 )
2680         {
2681           mapEl_setLi.erase( tr3 );
2682           mapLi_listEl.erase( *link13 );
2683           if ( tr1->NbNodes() == 3 ) {
2684             const SMDS_MeshElement* newElem = 0;
2685             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2686             myLastCreatedElems.Append(newElem);
2687             AddToSameGroups( newElem, tr1, aMesh );
2688             int aShapeId = tr1->getshapeId();
2689             if ( aShapeId )
2690               aMesh->SetMeshElementOnShape( newElem, aShapeId );
2691             aMesh->RemoveElement( tr1 );
2692             aMesh->RemoveElement( tr3 );
2693           }
2694           else {
2695             vector< const SMDS_MeshNode* > N1;
2696             vector< const SMDS_MeshNode* > N2;
2697             getNodesFromTwoTria(tr1,tr3,N1,N2);
2698             // now we receive following N1 and N2 (using numeration as above image)
2699             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2700             // i.e. first nodes from both arrays form a new diagonal
2701             const SMDS_MeshNode* aNodes[8];
2702             aNodes[0] = N1[0];
2703             aNodes[1] = N1[1];
2704             aNodes[2] = N2[0];
2705             aNodes[3] = N2[1];
2706             aNodes[4] = N1[3];
2707             aNodes[5] = N2[5];
2708             aNodes[6] = N2[3];
2709             aNodes[7] = N1[5];
2710             const SMDS_MeshElement* newElem = 0;
2711             if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
2712               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2713                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
2714             else
2715               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2716                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2717             myLastCreatedElems.Append(newElem);
2718             AddToSameGroups( newElem, tr1, aMesh );
2719             int aShapeId = tr1->getshapeId();
2720             if ( aShapeId )
2721               aMesh->SetMeshElementOnShape( newElem, aShapeId );
2722             aMesh->RemoveElement( tr1 );
2723             aMesh->RemoveElement( tr3 );
2724             // remove middle node (9)
2725             if ( N1[4]->NbInverseElements() == 0 )
2726               aMesh->RemoveNode( N1[4] );
2727             if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
2728               aMesh->RemoveNode( N1[6] );
2729             if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
2730               aMesh->RemoveNode( N2[6] );
2731           }
2732         }
2733
2734         // Next element to fuse: the rejected one
2735         if ( tr3 )
2736           startElem = Ok12 ? tr3 : tr2;
2737
2738       } // if ( startElem )
2739     } // while ( startElem || !startLinks.empty() )
2740   } // while ( ! mapEl_setLi.empty() )
2741
2742   return true;
2743 }
2744
2745
2746 /*#define DUMPSO(txt) \
2747 //  cout << txt << endl;
2748 //=============================================================================
2749 //
2750 //
2751 //
2752 //=============================================================================
2753 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2754 {
2755 if ( i1 == i2 )
2756 return;
2757 int tmp = idNodes[ i1 ];
2758 idNodes[ i1 ] = idNodes[ i2 ];
2759 idNodes[ i2 ] = tmp;
2760 gp_Pnt Ptmp = P[ i1 ];
2761 P[ i1 ] = P[ i2 ];
2762 P[ i2 ] = Ptmp;
2763 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2764 }
2765
2766 //=======================================================================
2767 //function : SortQuadNodes
2768 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2769 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2770 //           1 or 2 else 0.
2771 //=======================================================================
2772
2773 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2774 int               idNodes[] )
2775 {
2776   gp_Pnt P[4];
2777   int i;
2778   for ( i = 0; i < 4; i++ ) {
2779     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2780     if ( !n ) return 0;
2781     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2782   }
2783
2784   gp_Vec V1(P[0], P[1]);
2785   gp_Vec V2(P[0], P[2]);
2786   gp_Vec V3(P[0], P[3]);
2787
2788   gp_Vec Cross1 = V1 ^ V2;
2789   gp_Vec Cross2 = V2 ^ V3;
2790
2791   i = 0;
2792   if (Cross1.Dot(Cross2) < 0)
2793   {
2794     Cross1 = V2 ^ V1;
2795     Cross2 = V1 ^ V3;
2796
2797     if (Cross1.Dot(Cross2) < 0)
2798       i = 2;
2799     else
2800       i = 1;
2801     swap ( i, i + 1, idNodes, P );
2802
2803     //     for ( int ii = 0; ii < 4; ii++ ) {
2804     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2805     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2806     //     }
2807   }
2808   return i;
2809 }
2810
2811 //=======================================================================
2812 //function : SortHexaNodes
2813 //purpose  : Set 8 nodes of a hexahedron in a good order.
2814 //           Return success status
2815 //=======================================================================
2816
2817 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2818                                       int               idNodes[] )
2819 {
2820   gp_Pnt P[8];
2821   int i;
2822   DUMPSO( "INPUT: ========================================");
2823   for ( i = 0; i < 8; i++ ) {
2824     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2825     if ( !n ) return false;
2826     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2827     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2828   }
2829   DUMPSO( "========================================");
2830
2831
2832   set<int> faceNodes;  // ids of bottom face nodes, to be found
2833   set<int> checkedId1; // ids of tried 2-nd nodes
2834   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2835   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2836   int iMin, iLoop1 = 0;
2837
2838   // Loop to try the 2-nd nodes
2839
2840   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2841   {
2842     // Find not checked 2-nd node
2843     for ( i = 1; i < 8; i++ )
2844       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2845         int id1 = idNodes[i];
2846         swap ( 1, i, idNodes, P );
2847         checkedId1.insert ( id1 );
2848         break;
2849       }
2850
2851     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2852     // ie that all but meybe one (id3 which is on the same face) nodes
2853     // lay on the same side from the triangle plane.
2854
2855     bool manyInPlane = false; // more than 4 nodes lay in plane
2856     int iLoop2 = 0;
2857     while ( ++iLoop2 < 6 ) {
2858
2859       // get 1-2-3 plane coeffs
2860       Standard_Real A, B, C, D;
2861       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2862       if ( N.SquareMagnitude() > gp::Resolution() )
2863       {
2864         gp_Pln pln ( P[0], N );
2865         pln.Coefficients( A, B, C, D );
2866
2867         // find the node (iMin) closest to pln
2868         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2869         set<int> idInPln;
2870         for ( i = 3; i < 8; i++ ) {
2871           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2872           if ( fabs( dist[i] ) < minDist ) {
2873             minDist = fabs( dist[i] );
2874             iMin = i;
2875           }
2876           if ( fabs( dist[i] ) <= tol )
2877             idInPln.insert( idNodes[i] );
2878         }
2879
2880         // there should not be more than 4 nodes in bottom plane
2881         if ( idInPln.size() > 1 )
2882         {
2883           DUMPSO( "### idInPln.size() = " << idInPln.size());
2884           // idInPlane does not contain the first 3 nodes
2885           if ( manyInPlane || idInPln.size() == 5)
2886             return false; // all nodes in one plane
2887           manyInPlane = true;
2888
2889           // set the 1-st node to be not in plane
2890           for ( i = 3; i < 8; i++ ) {
2891             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2892               DUMPSO( "### Reset 0-th node");
2893               swap( 0, i, idNodes, P );
2894               break;
2895             }
2896           }
2897
2898           // reset to re-check second nodes
2899           leastDist = DBL_MAX;
2900           faceNodes.clear();
2901           checkedId1.clear();
2902           iLoop1 = 0;
2903           break; // from iLoop2;
2904         }
2905
2906         // check that the other 4 nodes are on the same side
2907         bool sameSide = true;
2908         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2909         for ( i = 3; sameSide && i < 8; i++ ) {
2910           if ( i != iMin )
2911             sameSide = ( isNeg == dist[i] <= 0.);
2912         }
2913
2914         // keep best solution
2915         if ( sameSide && minDist < leastDist ) {
2916           leastDist = minDist;
2917           faceNodes.clear();
2918           faceNodes.insert( idNodes[ 1 ] );
2919           faceNodes.insert( idNodes[ 2 ] );
2920           faceNodes.insert( idNodes[ iMin ] );
2921           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2922                   << " leastDist = " << leastDist);
2923           if ( leastDist <= DBL_MIN )
2924             break;
2925         }
2926       }
2927
2928       // set next 3-d node to check
2929       int iNext = 2 + iLoop2;
2930       if ( iNext < 8 ) {
2931         DUMPSO( "Try 2-nd");
2932         swap ( 2, iNext, idNodes, P );
2933       }
2934     } // while ( iLoop2 < 6 )
2935   } // iLoop1
2936
2937   if ( faceNodes.empty() ) return false;
2938
2939   // Put the faceNodes in proper places
2940   for ( i = 4; i < 8; i++ ) {
2941     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2942       // find a place to put
2943       int iTo = 1;
2944       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2945         iTo++;
2946       DUMPSO( "Set faceNodes");
2947       swap ( iTo, i, idNodes, P );
2948     }
2949   }
2950
2951
2952   // Set nodes of the found bottom face in good order
2953   DUMPSO( " Found bottom face: ");
2954   i = SortQuadNodes( theMesh, idNodes );
2955   if ( i ) {
2956     gp_Pnt Ptmp = P[ i ];
2957     P[ i ] = P[ i+1 ];
2958     P[ i+1 ] = Ptmp;
2959   }
2960   //   else
2961   //     for ( int ii = 0; ii < 4; ii++ ) {
2962   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2963   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2964   //    }
2965
2966   // Gravity center of the top and bottom faces
2967   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2968   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2969
2970   // Get direction from the bottom to the top face
2971   gp_Vec upDir ( aGCb, aGCt );
2972   Standard_Real upDirSize = upDir.Magnitude();
2973   if ( upDirSize <= gp::Resolution() ) return false;
2974   upDir / upDirSize;
2975
2976   // Assure that the bottom face normal points up
2977   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2978   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2979   if ( Nb.Dot( upDir ) < 0 ) {
2980     DUMPSO( "Reverse bottom face");
2981     swap( 1, 3, idNodes, P );
2982   }
2983
2984   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2985   Standard_Real minDist = DBL_MAX;
2986   for ( i = 4; i < 8; i++ ) {
2987     // projection of P[i] to the plane defined by P[0] and upDir
2988     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2989     Standard_Real sqDist = P[0].SquareDistance( Pp );
2990     if ( sqDist < minDist ) {
2991       minDist = sqDist;
2992       iMin = i;
2993     }
2994   }
2995   DUMPSO( "Set 4-th");
2996   swap ( 4, iMin, idNodes, P );
2997
2998   // Set nodes of the top face in good order
2999   DUMPSO( "Sort top face");
3000   i = SortQuadNodes( theMesh, &idNodes[4] );
3001   if ( i ) {
3002     i += 4;
3003     gp_Pnt Ptmp = P[ i ];
3004     P[ i ] = P[ i+1 ];
3005     P[ i+1 ] = Ptmp;
3006   }
3007
3008   // Assure that direction of the top face normal is from the bottom face
3009   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
3010   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
3011   if ( Nt.Dot( upDir ) < 0 ) {
3012     DUMPSO( "Reverse top face");
3013     swap( 5, 7, idNodes, P );
3014   }
3015
3016   //   DUMPSO( "OUTPUT: ========================================");
3017   //   for ( i = 0; i < 8; i++ ) {
3018   //     float *p = ugrid->GetPoint(idNodes[i]);
3019   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
3020   //   }
3021
3022   return true;
3023 }*/
3024
3025 //================================================================================
3026 /*!
3027  * \brief Return nodes linked to the given one
3028  * \param theNode - the node
3029  * \param linkedNodes - the found nodes
3030  * \param type - the type of elements to check
3031  *
3032  * Medium nodes are ignored
3033  */
3034 //================================================================================
3035
3036 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
3037                                        TIDSortedElemSet &   linkedNodes,
3038                                        SMDSAbs_ElementType  type )
3039 {
3040   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
3041   while ( elemIt->more() )
3042   {
3043     const SMDS_MeshElement* elem = elemIt->next();
3044     if(elem->GetType() == SMDSAbs_0DElement)
3045       continue;
3046
3047     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
3048     if ( elem->GetType() == SMDSAbs_Volume )
3049     {
3050       SMDS_VolumeTool vol( elem );
3051       while ( nodeIt->more() ) {
3052         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
3053         if ( theNode != n && vol.IsLinked( theNode, n ))
3054           linkedNodes.insert( n );
3055       }
3056     }
3057     else
3058     {
3059       for ( int i = 0; nodeIt->more(); ++i ) {
3060         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
3061         if ( n == theNode ) {
3062           int iBefore = i - 1;
3063           int iAfter  = i + 1;
3064           if ( elem->IsQuadratic() ) {
3065             int nb = elem->NbNodes() / 2;
3066             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
3067             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
3068           }
3069           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
3070           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
3071         }
3072       }
3073     }
3074   }
3075 }
3076
3077 //=======================================================================
3078 //function : laplacianSmooth
3079 //purpose  : pulls theNode toward the center of surrounding nodes directly
3080 //           connected to that node along an element edge
3081 //=======================================================================
3082
3083 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
3084                      const Handle(Geom_Surface)&          theSurface,
3085                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3086 {
3087   // find surrounding nodes
3088
3089   TIDSortedElemSet nodeSet;
3090   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
3091
3092   // compute new coodrs
3093
3094   double coord[] = { 0., 0., 0. };
3095   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
3096   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
3097     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
3098     if ( theSurface.IsNull() ) { // smooth in 3D
3099       coord[0] += node->X();
3100       coord[1] += node->Y();
3101       coord[2] += node->Z();
3102     }
3103     else { // smooth in 2D
3104       ASSERT( theUVMap.find( node ) != theUVMap.end() );
3105       gp_XY* uv = theUVMap[ node ];
3106       coord[0] += uv->X();
3107       coord[1] += uv->Y();
3108     }
3109   }
3110   int nbNodes = nodeSet.size();
3111   if ( !nbNodes )
3112     return;
3113   coord[0] /= nbNodes;
3114   coord[1] /= nbNodes;
3115
3116   if ( !theSurface.IsNull() ) {
3117     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
3118     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
3119     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
3120     coord[0] = p3d.X();
3121     coord[1] = p3d.Y();
3122     coord[2] = p3d.Z();
3123   }
3124   else
3125     coord[2] /= nbNodes;
3126
3127   // move node
3128
3129   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
3130 }
3131
3132 //=======================================================================
3133 //function : centroidalSmooth
3134 //purpose  : pulls theNode toward the element-area-weighted centroid of the
3135 //           surrounding elements
3136 //=======================================================================
3137
3138 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
3139                       const Handle(Geom_Surface)&          theSurface,
3140                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3141 {
3142   gp_XYZ aNewXYZ(0.,0.,0.);
3143   SMESH::Controls::Area anAreaFunc;
3144   double totalArea = 0.;
3145   int nbElems = 0;
3146
3147   // compute new XYZ
3148
3149   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
3150   while ( elemIt->more() )
3151   {
3152     const SMDS_MeshElement* elem = elemIt->next();
3153     nbElems++;
3154
3155     gp_XYZ elemCenter(0.,0.,0.);
3156     SMESH::Controls::TSequenceOfXYZ aNodePoints;
3157     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3158     int nn = elem->NbNodes();
3159     if(elem->IsQuadratic()) nn = nn/2;
3160     int i=0;
3161     //while ( itN->more() ) {
3162     while ( i<nn ) {
3163       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
3164       i++;
3165       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
3166       aNodePoints.push_back( aP );
3167       if ( !theSurface.IsNull() ) { // smooth in 2D
3168         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
3169         gp_XY* uv = theUVMap[ aNode ];
3170         aP.SetCoord( uv->X(), uv->Y(), 0. );
3171       }
3172       elemCenter += aP;
3173     }
3174     double elemArea = anAreaFunc.GetValue( aNodePoints );
3175     totalArea += elemArea;
3176     elemCenter /= nn;
3177     aNewXYZ += elemCenter * elemArea;
3178   }
3179   aNewXYZ /= totalArea;
3180   if ( !theSurface.IsNull() ) {
3181     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
3182     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
3183   }
3184
3185   // move node
3186
3187   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
3188 }
3189
3190 //=======================================================================
3191 //function : getClosestUV
3192 //purpose  : return UV of closest projection
3193 //=======================================================================
3194
3195 static bool getClosestUV (Extrema_GenExtPS& projector,
3196                           const gp_Pnt&     point,
3197                           gp_XY &           result)
3198 {
3199   projector.Perform( point );
3200   if ( projector.IsDone() ) {
3201     double u, v, minVal = DBL_MAX;
3202     for ( int i = projector.NbExt(); i > 0; i-- )
3203 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
3204       if ( projector.SquareDistance( i ) < minVal ) {
3205         minVal = projector.SquareDistance( i );
3206 #else
3207       if ( projector.Value( i ) < minVal ) {
3208         minVal = projector.Value( i );
3209 #endif
3210         projector.Point( i ).Parameter( u, v );
3211       }
3212     result.SetCoord( u, v );
3213     return true;
3214   }
3215   return false;
3216 }
3217
3218 //=======================================================================
3219 //function : Smooth
3220 //purpose  : Smooth theElements during theNbIterations or until a worst
3221 //           element has aspect ratio <= theTgtAspectRatio.
3222 //           Aspect Ratio varies in range [1.0, inf].
3223 //           If theElements is empty, the whole mesh is smoothed.
3224 //           theFixedNodes contains additionally fixed nodes. Nodes built
3225 //           on edges and boundary nodes are always fixed.
3226 //=======================================================================
3227
3228 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
3229                                set<const SMDS_MeshNode*> & theFixedNodes,
3230                                const SmoothMethod          theSmoothMethod,
3231                                const int                   theNbIterations,
3232                                double                      theTgtAspectRatio,
3233                                const bool                  the2D)
3234 {
3235   myLastCreatedElems.Clear();
3236   myLastCreatedNodes.Clear();
3237
3238   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
3239
3240   if ( theTgtAspectRatio < 1.0 )
3241     theTgtAspectRatio = 1.0;
3242
3243   const double disttol = 1.e-16;
3244
3245   SMESH::Controls::AspectRatio aQualityFunc;
3246
3247   SMESHDS_Mesh* aMesh = GetMeshDS();
3248
3249   if ( theElems.empty() ) {
3250     // add all faces to theElems
3251     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
3252     while ( fIt->more() ) {
3253       const SMDS_MeshElement* face = fIt->next();
3254       theElems.insert( theElems.end(), face );
3255     }
3256   }
3257   // get all face ids theElems are on
3258   set< int > faceIdSet;
3259   TIDSortedElemSet::iterator itElem;
3260   if ( the2D )
3261     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3262       int fId = FindShape( *itElem );
3263       // check that corresponding submesh exists and a shape is face
3264       if (fId &&
3265           faceIdSet.find( fId ) == faceIdSet.end() &&
3266           aMesh->MeshElements( fId )) {
3267         TopoDS_Shape F = aMesh->IndexToShape( fId );
3268         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
3269           faceIdSet.insert( fId );
3270       }
3271     }
3272   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
3273
3274   // ===============================================
3275   // smooth elements on each TopoDS_Face separately
3276   // ===============================================
3277
3278   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
3279   for ( ; fId != faceIdSet.rend(); ++fId ) {
3280     // get face surface and submesh
3281     Handle(Geom_Surface) surface;
3282     SMESHDS_SubMesh* faceSubMesh = 0;
3283     TopoDS_Face face;
3284     double fToler2 = 0, f,l;
3285     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
3286     bool isUPeriodic = false, isVPeriodic = false;
3287     if ( *fId ) {
3288       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
3289       surface = BRep_Tool::Surface( face );
3290       faceSubMesh = aMesh->MeshElements( *fId );
3291       fToler2 = BRep_Tool::Tolerance( face );
3292       fToler2 *= fToler2 * 10.;
3293       isUPeriodic = surface->IsUPeriodic();
3294       if ( isUPeriodic )
3295         surface->UPeriod();
3296       isVPeriodic = surface->IsVPeriodic();
3297       if ( isVPeriodic )
3298         surface->VPeriod();
3299       surface->Bounds( u1, u2, v1, v2 );
3300     }
3301     // ---------------------------------------------------------
3302     // for elements on a face, find movable and fixed nodes and
3303     // compute UV for them
3304     // ---------------------------------------------------------
3305     bool checkBoundaryNodes = false;
3306     bool isQuadratic = false;
3307     set<const SMDS_MeshNode*> setMovableNodes;
3308     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3309     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3310     list< const SMDS_MeshElement* > elemsOnFace;
3311
3312     Extrema_GenExtPS projector;
3313     GeomAdaptor_Surface surfAdaptor;
3314     if ( !surface.IsNull() ) {
3315       surfAdaptor.Load( surface );
3316       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3317     }
3318     int nbElemOnFace = 0;
3319     itElem = theElems.begin();
3320     // loop on not yet smoothed elements: look for elems on a face
3321     while ( itElem != theElems.end() ) {
3322       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3323         break; // all elements found
3324
3325       const SMDS_MeshElement* elem = *itElem;
3326       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3327            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3328         ++itElem;
3329         continue;
3330       }
3331       elemsOnFace.push_back( elem );
3332       theElems.erase( itElem++ );
3333       nbElemOnFace++;
3334
3335       if ( !isQuadratic )
3336         isQuadratic = elem->IsQuadratic();
3337
3338       // get movable nodes of elem
3339       const SMDS_MeshNode* node;
3340       SMDS_TypeOfPosition posType;
3341       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3342       int nn = 0, nbn =  elem->NbNodes();
3343       if(elem->IsQuadratic())
3344         nbn = nbn/2;
3345       while ( nn++ < nbn ) {
3346         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3347         const SMDS_PositionPtr& pos = node->GetPosition();
3348         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3349         if (posType != SMDS_TOP_EDGE &&
3350             posType != SMDS_TOP_VERTEX &&
3351             theFixedNodes.find( node ) == theFixedNodes.end())
3352         {
3353           // check if all faces around the node are on faceSubMesh
3354           // because a node on edge may be bound to face
3355           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3356           bool all = true;
3357           if ( faceSubMesh ) {
3358             while ( eIt->more() && all ) {
3359               const SMDS_MeshElement* e = eIt->next();
3360               all = faceSubMesh->Contains( e );
3361             }
3362           }
3363           if ( all )
3364             setMovableNodes.insert( node );
3365           else
3366             checkBoundaryNodes = true;
3367         }
3368         if ( posType == SMDS_TOP_3DSPACE )
3369           checkBoundaryNodes = true;
3370       }
3371
3372       if ( surface.IsNull() )
3373         continue;
3374
3375       // get nodes to check UV
3376       list< const SMDS_MeshNode* > uvCheckNodes;
3377       itN = elem->nodesIterator();
3378       nn = 0; nbn =  elem->NbNodes();
3379       if(elem->IsQuadratic())
3380         nbn = nbn/2;
3381       while ( nn++ < nbn ) {
3382         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3383         if ( uvMap.find( node ) == uvMap.end() )
3384           uvCheckNodes.push_back( node );
3385         // add nodes of elems sharing node
3386         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3387         //         while ( eIt->more() ) {
3388         //           const SMDS_MeshElement* e = eIt->next();
3389         //           if ( e != elem ) {
3390         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3391         //             while ( nIt->more() ) {
3392         //               const SMDS_MeshNode* n =
3393         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3394         //               if ( uvMap.find( n ) == uvMap.end() )
3395         //                 uvCheckNodes.push_back( n );
3396         //             }
3397         //           }
3398         //         }
3399       }
3400       // check UV on face
3401       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3402       for ( ; n != uvCheckNodes.end(); ++n ) {
3403         node = *n;
3404         gp_XY uv( 0, 0 );
3405         const SMDS_PositionPtr& pos = node->GetPosition();
3406         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3407         // get existing UV
3408         switch ( posType ) {
3409         case SMDS_TOP_FACE: {
3410           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3411           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3412           break;
3413         }
3414         case SMDS_TOP_EDGE: {
3415           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3416           Handle(Geom2d_Curve) pcurve;
3417           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3418             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3419           if ( !pcurve.IsNull() ) {
3420             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3421             uv = pcurve->Value( u ).XY();
3422           }
3423           break;
3424         }
3425         case SMDS_TOP_VERTEX: {
3426           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3427           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3428             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3429           break;
3430         }
3431         default:;
3432         }
3433         // check existing UV
3434         bool project = true;
3435         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3436         double dist1 = DBL_MAX, dist2 = 0;
3437         if ( posType != SMDS_TOP_3DSPACE ) {
3438           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3439           project = dist1 > fToler2;
3440         }
3441         if ( project ) { // compute new UV
3442           gp_XY newUV;
3443           if ( !getClosestUV( projector, pNode, newUV )) {
3444             MESSAGE("Node Projection Failed " << node);
3445           }
3446           else {
3447             if ( isUPeriodic )
3448               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3449             if ( isVPeriodic )
3450               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3451             // check new UV
3452             if ( posType != SMDS_TOP_3DSPACE )
3453               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3454             if ( dist2 < dist1 )
3455               uv = newUV;
3456           }
3457         }
3458         // store UV in the map
3459         listUV.push_back( uv );
3460         uvMap.insert( make_pair( node, &listUV.back() ));
3461       }
3462     } // loop on not yet smoothed elements
3463
3464     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3465       checkBoundaryNodes = true;
3466
3467     // fix nodes on mesh boundary
3468
3469     if ( checkBoundaryNodes ) {
3470       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3471       map< SMESH_TLink, int >::iterator link_nb;
3472       // put all elements links to linkNbMap
3473       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3474       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3475         const SMDS_MeshElement* elem = (*elemIt);
3476         int nbn =  elem->NbCornerNodes();
3477         // loop on elem links: insert them in linkNbMap
3478         for ( int iN = 0; iN < nbn; ++iN ) {
3479           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3480           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3481           SMESH_TLink link( n1, n2 );
3482           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3483           link_nb->second++;
3484         }
3485       }
3486       // remove nodes that are in links encountered only once from setMovableNodes
3487       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3488         if ( link_nb->second == 1 ) {
3489           setMovableNodes.erase( link_nb->first.node1() );
3490           setMovableNodes.erase( link_nb->first.node2() );
3491         }
3492       }
3493     }
3494
3495     // -----------------------------------------------------
3496     // for nodes on seam edge, compute one more UV ( uvMap2 );
3497     // find movable nodes linked to nodes on seam and which
3498     // are to be smoothed using the second UV ( uvMap2 )
3499     // -----------------------------------------------------
3500
3501     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3502     if ( !surface.IsNull() ) {
3503       TopExp_Explorer eExp( face, TopAbs_EDGE );
3504       for ( ; eExp.More(); eExp.Next() ) {
3505         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3506         if ( !BRep_Tool::IsClosed( edge, face ))
3507           continue;
3508         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3509         if ( !sm ) continue;
3510         // find out which parameter varies for a node on seam
3511         double f,l;
3512         gp_Pnt2d uv1, uv2;
3513         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3514         if ( pcurve.IsNull() ) continue;
3515         uv1 = pcurve->Value( f );
3516         edge.Reverse();
3517         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3518         if ( pcurve.IsNull() ) continue;
3519         uv2 = pcurve->Value( f );
3520         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3521         // assure uv1 < uv2
3522         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3523           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3524         }
3525         // get nodes on seam and its vertices
3526         list< const SMDS_MeshNode* > seamNodes;
3527         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3528         while ( nSeamIt->more() ) {
3529           const SMDS_MeshNode* node = nSeamIt->next();
3530           if ( !isQuadratic || !IsMedium( node ))
3531             seamNodes.push_back( node );
3532         }
3533         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3534         for ( ; vExp.More(); vExp.Next() ) {
3535           sm = aMesh->MeshElements( vExp.Current() );
3536           if ( sm ) {
3537             nSeamIt = sm->GetNodes();
3538             while ( nSeamIt->more() )
3539               seamNodes.push_back( nSeamIt->next() );
3540           }
3541         }
3542         // loop on nodes on seam
3543         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3544         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3545           const SMDS_MeshNode* nSeam = *noSeIt;
3546           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3547           if ( n_uv == uvMap.end() )
3548             continue;
3549           // set the first UV
3550           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3551           // set the second UV
3552           listUV.push_back( *n_uv->second );
3553           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3554           if ( uvMap2.empty() )
3555             uvMap2 = uvMap; // copy the uvMap contents
3556           uvMap2[ nSeam ] = &listUV.back();
3557
3558           // collect movable nodes linked to ones on seam in nodesNearSeam
3559           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3560           while ( eIt->more() ) {
3561             const SMDS_MeshElement* e = eIt->next();
3562             int nbUseMap1 = 0, nbUseMap2 = 0;
3563             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3564             int nn = 0, nbn =  e->NbNodes();
3565             if(e->IsQuadratic()) nbn = nbn/2;
3566             while ( nn++ < nbn )
3567             {
3568               const SMDS_MeshNode* n =
3569                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3570               if (n == nSeam ||
3571                   setMovableNodes.find( n ) == setMovableNodes.end() )
3572                 continue;
3573               // add only nodes being closer to uv2 than to uv1
3574               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3575                            0.5 * ( n->Y() + nSeam->Y() ),
3576                            0.5 * ( n->Z() + nSeam->Z() ));
3577               gp_XY uv;
3578               getClosestUV( projector, pMid, uv );
3579               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3580                 nodesNearSeam.insert( n );
3581                 nbUseMap2++;
3582               }
3583               else
3584                 nbUseMap1++;
3585             }
3586             // for centroidalSmooth all element nodes must
3587             // be on one side of a seam
3588             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3589               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3590               nn = 0;
3591               while ( nn++ < nbn ) {
3592                 const SMDS_MeshNode* n =
3593                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3594                 setMovableNodes.erase( n );
3595               }
3596             }
3597           }
3598         } // loop on nodes on seam
3599       } // loop on edge of a face
3600     } // if ( !face.IsNull() )
3601
3602     if ( setMovableNodes.empty() ) {
3603       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3604       continue; // goto next face
3605     }
3606
3607     // -------------
3608     // SMOOTHING //
3609     // -------------
3610
3611     int it = -1;
3612     double maxRatio = -1., maxDisplacement = -1.;
3613     set<const SMDS_MeshNode*>::iterator nodeToMove;
3614     for ( it = 0; it < theNbIterations; it++ ) {
3615       maxDisplacement = 0.;
3616       nodeToMove = setMovableNodes.begin();
3617       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3618         const SMDS_MeshNode* node = (*nodeToMove);
3619         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3620
3621         // smooth
3622         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3623         if ( theSmoothMethod == LAPLACIAN )
3624           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3625         else
3626           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3627
3628         // node displacement
3629         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3630         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3631         if ( aDispl > maxDisplacement )
3632           maxDisplacement = aDispl;
3633       }
3634       // no node movement => exit
3635       //if ( maxDisplacement < 1.e-16 ) {
3636       if ( maxDisplacement < disttol ) {
3637         MESSAGE("-- no node movement --");
3638         break;
3639       }
3640
3641       // check elements quality
3642       maxRatio  = 0;
3643       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3644       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3645         const SMDS_MeshElement* elem = (*elemIt);
3646         if ( !elem || elem->GetType() != SMDSAbs_Face )
3647           continue;
3648         SMESH::Controls::TSequenceOfXYZ aPoints;
3649         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3650           double aValue = aQualityFunc.GetValue( aPoints );
3651           if ( aValue > maxRatio )
3652             maxRatio = aValue;
3653         }
3654       }
3655       if ( maxRatio <= theTgtAspectRatio ) {
3656         MESSAGE("-- quality achived --");
3657         break;
3658       }
3659       if (it+1 == theNbIterations) {
3660         MESSAGE("-- Iteration limit exceeded --");
3661       }
3662     } // smoothing iterations
3663
3664     MESSAGE(" Face id: " << *fId <<
3665             " Nb iterstions: " << it <<
3666             " Displacement: " << maxDisplacement <<
3667             " Aspect Ratio " << maxRatio);
3668
3669     // ---------------------------------------
3670     // new nodes positions are computed,
3671     // record movement in DS and set new UV
3672     // ---------------------------------------
3673     nodeToMove = setMovableNodes.begin();
3674     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3675       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3676       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3677       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3678       if ( node_uv != uvMap.end() ) {
3679         gp_XY* uv = node_uv->second;
3680         node->SetPosition
3681           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3682       }
3683     }
3684
3685     // move medium nodes of quadratic elements
3686     if ( isQuadratic )
3687     {
3688       SMESH_MesherHelper helper( *GetMesh() );
3689       helper.SetSubShape( face );
3690       vector<const SMDS_MeshNode*> nodes;
3691       bool checkUV;
3692       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3693       for ( ; elemIt != elemsOnFace.end(); ++elemIt )
3694       {
3695         const SMDS_MeshElement* QF = *elemIt;
3696         if ( QF->IsQuadratic() )
3697         {
3698           nodes.assign( SMDS_MeshElement::iterator( QF->interlacedNodesElemIterator() ),
3699                         SMDS_MeshElement::iterator() );
3700           nodes.push_back( nodes[0] );
3701           gp_Pnt xyz;
3702           for (size_t i = 1; i < nodes.size(); i += 2 ) // i points to a medium node
3703           {
3704             if ( !surface.IsNull() )
3705             {
3706               gp_XY uv1 = helper.GetNodeUV( face, nodes[i-1], nodes[i+1], &checkUV );
3707               gp_XY uv2 = helper.GetNodeUV( face, nodes[i+1], nodes[i-1], &checkUV );
3708               gp_XY uv  = helper.GetMiddleUV( surface, uv1, uv2 );
3709               xyz = surface->Value( uv.X(), uv.Y() );
3710             }
3711             else {
3712               xyz = 0.5 * ( SMESH_TNodeXYZ( nodes[i-1] ) + SMESH_TNodeXYZ( nodes[i+1] ));
3713             }
3714             if (( SMESH_TNodeXYZ( nodes[i] ) - xyz.XYZ() ).Modulus() > disttol )
3715               // we have to move a medium node
3716               aMesh->MoveNode( nodes[i], xyz.X(), xyz.Y(), xyz.Z() );
3717           }
3718         }
3719       }
3720     }
3721
3722   } // loop on face ids
3723
3724 }
3725
3726 //=======================================================================
3727 //function : isReverse
3728 //purpose  : Return true if normal of prevNodes is not co-directied with
3729 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3730 //           iNotSame is where prevNodes and nextNodes are different.
3731 //           If result is true then future volume orientation is OK
3732 //=======================================================================
3733
3734 static bool isReverse(const SMDS_MeshElement*             face,
3735                       const vector<const SMDS_MeshNode*>& prevNodes,
3736                       const vector<const SMDS_MeshNode*>& nextNodes,
3737                       const int                           iNotSame)
3738 {
3739
3740   SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
3741   SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
3742   gp_XYZ extrDir( pN - pP ), faceNorm;
3743   SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false );
3744
3745   return faceNorm * extrDir < 0.0;
3746 }
3747
3748 //=======================================================================
3749 /*!
3750  * \brief Create elements by sweeping an element
3751  * \param elem - element to sweep
3752  * \param newNodesItVec - nodes generated from each node of the element
3753  * \param newElems - generated elements
3754  * \param nbSteps - number of sweeping steps
3755  * \param srcElements - to append elem for each generated element
3756  */
3757 //=======================================================================
3758
3759 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3760                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3761                                     list<const SMDS_MeshElement*>&        newElems,
3762                                     const int                             nbSteps,
3763                                     SMESH_SequenceOfElemPtr&              srcElements)
3764 {
3765   //MESSAGE("sweepElement " << nbSteps);
3766   SMESHDS_Mesh* aMesh = GetMeshDS();
3767
3768   const int           nbNodes = elem->NbNodes();
3769   const int         nbCorners = elem->NbCornerNodes();
3770   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of
3771                                                           polyhedron creation !!! */
3772   // Loop on elem nodes:
3773   // find new nodes and detect same nodes indices
3774   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3775   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3776   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3777   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3778
3779   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
3780   vector<int> sames(nbNodes);
3781   vector<bool> isSingleNode(nbNodes);
3782
3783   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3784     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
3785     const SMDS_MeshNode*                         node = nnIt->first;
3786     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3787     if ( listNewNodes.empty() )
3788       return;
3789
3790     itNN   [ iNode ] = listNewNodes.begin();
3791     prevNod[ iNode ] = node;
3792     nextNod[ iNode ] = listNewNodes.front();
3793
3794     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
3795                                                              corner node of linear */
3796     if ( prevNod[ iNode ] != nextNod [ iNode ])
3797       nbDouble += !isSingleNode[iNode];
3798
3799     if( iNode < nbCorners ) { // check corners only
3800       if ( prevNod[ iNode ] == nextNod [ iNode ])
3801         sames[nbSame++] = iNode;
3802       else
3803         iNotSameNode = iNode;
3804     }
3805   }
3806
3807   if ( nbSame == nbNodes || nbSame > 2) {
3808     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3809     return;
3810   }
3811
3812   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
3813   {
3814     // fix nodes order to have bottom normal external
3815     if ( baseType == SMDSEntity_Polygon )
3816     {
3817       std::reverse( itNN.begin(), itNN.end() );
3818       std::reverse( prevNod.begin(), prevNod.end() );
3819       std::reverse( midlNod.begin(), midlNod.end() );
3820       std::reverse( nextNod.begin(), nextNod.end() );
3821       std::reverse( isSingleNode.begin(), isSingleNode.end() );
3822     }
3823     else
3824     {
3825       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
3826       SMDS_MeshCell::applyInterlace( ind, itNN );
3827       SMDS_MeshCell::applyInterlace( ind, prevNod );
3828       SMDS_MeshCell::applyInterlace( ind, nextNod );
3829       SMDS_MeshCell::applyInterlace( ind, midlNod );
3830       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3831       if ( nbSame > 0 )
3832       {
3833         sames[nbSame] = iNotSameNode;
3834         for ( int j = 0; j <= nbSame; ++j )
3835           for ( size_t i = 0; i < ind.size(); ++i )
3836             if ( ind[i] == sames[j] )
3837             {
3838               sames[j] = i;
3839               break;
3840             }
3841         iNotSameNode = sames[nbSame];
3842       }
3843     }
3844   }
3845
3846   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3847   if ( nbSame > 0 ) {
3848     iSameNode    = sames[ nbSame-1 ];
3849     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
3850     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
3851     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3852   }
3853
3854   // make new elements
3855   for (int iStep = 0; iStep < nbSteps; iStep++ )
3856   {
3857     // get next nodes
3858     for ( iNode = 0; iNode < nbNodes; iNode++ )
3859     {
3860       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
3861       nextNod[ iNode ] = *itNN[ iNode ]++;
3862     }
3863
3864     SMDS_MeshElement* aNewElem = 0;
3865     /*if(!elem->IsPoly())*/ {
3866       switch ( baseType ) {
3867       case SMDSEntity_0D:
3868       case SMDSEntity_Node: { // sweep NODE
3869         if ( nbSame == 0 ) {
3870           if ( isSingleNode[0] )
3871             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3872           else
3873             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3874         }
3875         else
3876           return;
3877         break;
3878       }
3879       case SMDSEntity_Edge: { // sweep EDGE
3880         if ( nbDouble == 0 )
3881         {
3882           if ( nbSame == 0 ) // ---> quadrangle
3883             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3884                                       nextNod[ 1 ], nextNod[ 0 ] );
3885           else               // ---> triangle
3886             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3887                                       nextNod[ iNotSameNode ] );
3888         }
3889         else                 // ---> polygon
3890         {
3891           vector<const SMDS_MeshNode*> poly_nodes;
3892           poly_nodes.push_back( prevNod[0] );
3893           poly_nodes.push_back( prevNod[1] );
3894           if ( prevNod[1] != nextNod[1] )
3895           {
3896             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
3897             poly_nodes.push_back( nextNod[1] );
3898           }
3899           if ( prevNod[0] != nextNod[0] )
3900           {
3901             poly_nodes.push_back( nextNod[0] );
3902             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
3903           }
3904           switch ( poly_nodes.size() ) {
3905           case 3:
3906             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
3907             break;
3908           case 4:
3909             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
3910                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
3911             break;
3912           default:
3913             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
3914           }
3915         }
3916         break;
3917       }
3918       case SMDSEntity_Triangle: // TRIANGLE --->
3919         {
3920           if ( nbDouble > 0 ) break;
3921           if ( nbSame == 0 )       // ---> pentahedron
3922             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3923                                          nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
3924
3925           else if ( nbSame == 1 )  // ---> pyramid
3926             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3927                                          nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3928                                          nextNod[ iSameNode ]);
3929
3930           else // 2 same nodes:       ---> tetrahedron
3931             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3932                                          nextNod[ iNotSameNode ]);
3933           break;
3934         }
3935       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
3936         {
3937           if ( nbSame == 2 )
3938             return;
3939           if ( nbDouble+nbSame == 2 )
3940           {
3941             if(nbSame==0) {      // ---> quadratic quadrangle
3942               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3943                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
3944             }
3945             else { //(nbSame==1) // ---> quadratic triangle
3946               if(sames[0]==2) {
3947                 return; // medium node on axis
3948               }
3949               else if(sames[0]==0)
3950                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3951                                           nextNod[2], midlNod[1], prevNod[2]);
3952               else // sames[0]==1
3953                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3954                                           midlNod[0], nextNod[2], prevNod[2]);
3955             }
3956           }
3957           else if ( nbDouble == 3 )
3958           {
3959             if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
3960               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3961                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
3962             }
3963           }
3964           else
3965             return;
3966           break;
3967         }
3968       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
3969         if ( nbDouble > 0 ) break;
3970
3971         if ( nbSame == 0 )       // ---> hexahedron
3972           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
3973                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
3974
3975         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
3976           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3977                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3978                                        nextNod[ iSameNode ]);
3979           newElems.push_back( aNewElem );
3980           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
3981                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3982                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3983         }
3984         else if ( nbSame == 2 ) { // ---> pentahedron
3985           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3986             // iBeforeSame is same too
3987             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3988                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
3989                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3990           else
3991             // iAfterSame is same too
3992             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
3993                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3994                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3995         }
3996         break;
3997       }
3998       case SMDSEntity_Quad_Triangle:  // sweep (Bi)Quadratic TRIANGLE --->
3999       case SMDSEntity_BiQuad_Triangle: /* ??? */ { 
4000         if ( nbDouble+nbSame != 3 ) break;
4001         if(nbSame==0) {
4002           // --->  pentahedron with 15 nodes
4003           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
4004                                        nextNod[0], nextNod[1], nextNod[2],
4005                                        prevNod[3], prevNod[4], prevNod[5],
4006                                        nextNod[3], nextNod[4], nextNod[5],
4007                                        midlNod[0], midlNod[1], midlNod[2]);
4008         }
4009         else if(nbSame==1) {
4010           // --->  2d order pyramid of 13 nodes
4011           int apex = iSameNode;
4012           int i0 = ( apex + 1 ) % nbCorners;
4013           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
4014           int i0a = apex + 3;
4015           int i1a = i1 + 3;
4016           int i01 = i0 + 3;
4017           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
4018                                       nextNod[i0], nextNod[i1], prevNod[apex],
4019                                       prevNod[i01], midlNod[i0],
4020                                       nextNod[i01], midlNod[i1],
4021                                       prevNod[i1a], prevNod[i0a],
4022                                       nextNod[i0a], nextNod[i1a]);
4023         }
4024         else if(nbSame==2) {
4025           // --->  2d order tetrahedron of 10 nodes
4026           int n1 = iNotSameNode;
4027           int n2 = ( n1 + 1             ) % nbCorners;
4028           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
4029           int n12 = n1 + 3;
4030           int n23 = n2 + 3;
4031           int n31 = n3 + 3;
4032           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
4033                                        prevNod[n12], prevNod[n23], prevNod[n31],
4034                                        midlNod[n1], nextNod[n12], nextNod[n31]);
4035         }
4036         break;
4037       }
4038       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
4039         if( nbSame == 0 ) {
4040           if ( nbDouble != 4 ) break;
4041           // --->  hexahedron with 20 nodes
4042           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
4043                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
4044                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
4045                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
4046                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
4047         }
4048         else if(nbSame==1) {
4049           // ---> pyramid + pentahedron - can not be created since it is needed
4050           // additional middle node at the center of face
4051           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
4052           return;
4053         }
4054         else if( nbSame == 2 ) {
4055           if ( nbDouble != 2 ) break;
4056           // --->  2d order Pentahedron with 15 nodes
4057           int n1,n2,n4,n5;
4058           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
4059             // iBeforeSame is same too
4060             n1 = iBeforeSame;
4061             n2 = iOpposSame;
4062             n4 = iSameNode;
4063             n5 = iAfterSame;
4064           }
4065           else {
4066             // iAfterSame is same too
4067             n1 = iSameNode;
4068             n2 = iBeforeSame;
4069             n4 = iAfterSame;
4070             n5 = iOpposSame;
4071           }
4072           int n12 = n2 + 4;
4073           int n45 = n4 + 4;
4074           int n14 = n1 + 4;
4075           int n25 = n5 + 4;
4076           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
4077                                        prevNod[n4], prevNod[n5], nextNod[n5],
4078                                        prevNod[n12], midlNod[n2], nextNod[n12],
4079                                        prevNod[n45], midlNod[n5], nextNod[n45],
4080                                        prevNod[n14], prevNod[n25], nextNod[n25]);
4081         }
4082         break;
4083       }
4084       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
4085
4086         if( nbSame == 0 && nbDouble == 9 ) {
4087           // --->  tri-quadratic hexahedron with 27 nodes
4088           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
4089                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
4090                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
4091                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
4092                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
4093                                        prevNod[8], // bottom center
4094                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
4095                                        nextNod[8], // top center
4096                                        midlNod[8]);// elem center
4097         }
4098         else
4099         {
4100           return;
4101         }
4102         break;
4103       }
4104       case SMDSEntity_Polygon: { // sweep POLYGON
4105
4106         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
4107           // --->  hexagonal prism
4108           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
4109                                        prevNod[3], prevNod[4], prevNod[5],
4110                                        nextNod[0], nextNod[1], nextNod[2],
4111                                        nextNod[3], nextNod[4], nextNod[5]);
4112         }
4113         break;
4114       }
4115       case SMDSEntity_Ball:
4116         return;
4117
4118       default:
4119         break;
4120       }
4121     }
4122
4123     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
4124     {
4125       if ( baseType != SMDSEntity_Polygon )
4126       {
4127         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
4128         SMDS_MeshCell::applyInterlace( ind, prevNod );
4129         SMDS_MeshCell::applyInterlace( ind, nextNod );
4130         SMDS_MeshCell::applyInterlace( ind, midlNod );
4131         SMDS_MeshCell::applyInterlace( ind, itNN );
4132         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
4133         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
4134       }
4135       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
4136       vector<int> quantities (nbNodes + 2);
4137       polyedre_nodes.clear();
4138       quantities.clear();
4139
4140       // bottom of prism
4141       for (int inode = 0; inode < nbNodes; inode++)
4142         polyedre_nodes.push_back( prevNod[inode] );
4143       quantities.push_back( nbNodes );
4144
4145       // top of prism
4146       polyedre_nodes.push_back( nextNod[0] );
4147       for (int inode = nbNodes; inode-1; --inode )
4148         polyedre_nodes.push_back( nextNod[inode-1] );
4149       quantities.push_back( nbNodes );
4150
4151       // side faces
4152       for (int iface = 0; iface < nbNodes; iface++)
4153       {
4154         const int prevNbNodes = polyedre_nodes.size();
4155         int inextface = (iface+1) % nbNodes;
4156         polyedre_nodes.push_back( prevNod[inextface] );
4157         polyedre_nodes.push_back( prevNod[iface] );
4158         if ( prevNod[iface] != nextNod[iface] )
4159         {
4160           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
4161           polyedre_nodes.push_back( nextNod[iface] );
4162         }
4163         if ( prevNod[inextface] != nextNod[inextface] )
4164         {
4165           polyedre_nodes.push_back( nextNod[inextface] );
4166           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
4167         }
4168         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
4169         if ( nbFaceNodes > 2 )
4170           quantities.push_back( nbFaceNodes );
4171         else // degenerated face
4172           polyedre_nodes.resize( prevNbNodes );
4173       }
4174       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
4175     }
4176
4177     if ( aNewElem ) {
4178       newElems.push_back( aNewElem );
4179       myLastCreatedElems.Append(aNewElem);
4180       srcElements.Append( elem );
4181     }
4182
4183     // set new prev nodes
4184     for ( iNode = 0; iNode < nbNodes; iNode++ )
4185       prevNod[ iNode ] = nextNod[ iNode ];
4186
4187   } // for steps
4188 }
4189
4190 //=======================================================================
4191 /*!
4192  * \brief Create 1D and 2D elements around swept elements
4193  * \param mapNewNodes - source nodes and ones generated from them
4194  * \param newElemsMap - source elements and ones generated from them
4195  * \param elemNewNodesMap - nodes generated from each node of each element
4196  * \param elemSet - all swept elements
4197  * \param nbSteps - number of sweeping steps
4198  * \param srcElements - to append elem for each generated element
4199  */
4200 //=======================================================================
4201
4202 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
4203                                   TElemOfElemListMap &     newElemsMap,
4204                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
4205                                   TIDSortedElemSet&        elemSet,
4206                                   const int                nbSteps,
4207                                   SMESH_SequenceOfElemPtr& srcElements)
4208 {
4209   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
4210   SMESHDS_Mesh* aMesh = GetMeshDS();
4211
4212   // Find nodes belonging to only one initial element - sweep them into edges.
4213
4214   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
4215   for ( ; nList != mapNewNodes.end(); nList++ )
4216   {
4217     const SMDS_MeshNode* node =
4218       static_cast<const SMDS_MeshNode*>( nList->first );
4219     if ( newElemsMap.count( node ))
4220       continue; // node was extruded into edge
4221     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
4222     int nbInitElems = 0;
4223     const SMDS_MeshElement* el = 0;
4224     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
4225     while ( eIt->more() && nbInitElems < 2 ) {
4226       el = eIt->next();
4227       SMDSAbs_ElementType type = el->GetType();
4228       if ( type == SMDSAbs_Volume || type < highType ) continue;
4229       if ( type > highType ) {
4230         nbInitElems = 0;
4231         highType = type;
4232       }
4233       nbInitElems += elemSet.count(el);
4234     }
4235     if ( nbInitElems < 2 ) {
4236       bool NotCreateEdge = el && el->IsMediumNode(node);
4237       if(!NotCreateEdge) {
4238         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
4239         list<const SMDS_MeshElement*> newEdges;
4240         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
4241       }
4242     }
4243   }
4244
4245   // Make a ceiling for each element ie an equal element of last new nodes.
4246   // Find free links of faces - make edges and sweep them into faces.
4247
4248   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
4249   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
4250   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
4251   {
4252     const SMDS_MeshElement* elem = itElem->first;
4253     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
4254
4255     if(itElem->second.size()==0) continue;
4256
4257     const bool isQuadratic = elem->IsQuadratic();
4258
4259     if ( elem->GetType() == SMDSAbs_Edge ) {
4260       // create a ceiling edge
4261       if ( !isQuadratic ) {
4262         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4263                                vecNewNodes[ 1 ]->second.back())) {
4264           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4265                                                    vecNewNodes[ 1 ]->second.back()));
4266           srcElements.Append( elem );
4267         }
4268       }
4269       else {
4270         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4271                                vecNewNodes[ 1 ]->second.back(),
4272                                vecNewNodes[ 2 ]->second.back())) {
4273           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4274                                                    vecNewNodes[ 1 ]->second.back(),
4275                                                    vecNewNodes[ 2 ]->second.back()));
4276           srcElements.Append( elem );
4277         }
4278       }
4279     }
4280     if ( elem->GetType() != SMDSAbs_Face )
4281       continue;
4282
4283     bool hasFreeLinks = false;
4284
4285     TIDSortedElemSet avoidSet;
4286     avoidSet.insert( elem );
4287
4288     set<const SMDS_MeshNode*> aFaceLastNodes;
4289     int iNode, nbNodes = vecNewNodes.size();
4290     if ( !isQuadratic ) {
4291       // loop on the face nodes
4292       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4293         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4294         // look for free links of the face
4295         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4296         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4297         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4298         // check if a link n1-n2 is free
4299         if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4300           hasFreeLinks = true;
4301           // make a new edge and a ceiling for a new edge
4302           const SMDS_MeshElement* edge;
4303           if ( ! ( edge = aMesh->FindEdge( n1, n2 ))) {
4304             myLastCreatedElems.Append( edge = aMesh->AddEdge( n1, n2 )); // free link edge
4305             srcElements.Append( myLastCreatedElems.Last() );
4306           }
4307           n1 = vecNewNodes[ iNode ]->second.back();
4308           n2 = vecNewNodes[ iNext ]->second.back();
4309           if ( !aMesh->FindEdge( n1, n2 )) {
4310             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling
4311             srcElements.Append( edge );
4312           }
4313         }
4314       }
4315     }
4316     else { // elem is quadratic face
4317       int nbn = nbNodes/2;
4318       for ( iNode = 0; iNode < nbn; iNode++ ) {
4319         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4320         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4321         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4322         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4323         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4324         // check if a link is free
4325         if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4326              ! SMESH_MeshAlgos::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4327              ! SMESH_MeshAlgos::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4328           hasFreeLinks = true;
4329           // make an edge and a ceiling for a new edge
4330           // find medium node
4331           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4332             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4333             srcElements.Append( elem );
4334           }
4335           n1 = vecNewNodes[ iNode ]->second.back();
4336           n2 = vecNewNodes[ iNext ]->second.back();
4337           n3 = vecNewNodes[ iNode+nbn ]->second.back();
4338           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4339             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4340             srcElements.Append( elem );
4341           }
4342         }
4343       }
4344       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4345         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4346       }
4347     }
4348
4349     // sweep free links into faces
4350
4351     if ( hasFreeLinks )  {
4352       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4353       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4354
4355       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4356       set<const SMDS_MeshNode*> initNodeSetNoCenter/*, topNodeSetNoCenter*/;
4357       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4358         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4359         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4360       }
4361       if ( isQuadratic && nbNodes % 2 ) {  // node set for the case of a biquadratic
4362         initNodeSetNoCenter = initNodeSet; // swept face and a not biquadratic volume
4363         initNodeSetNoCenter.erase( vecNewNodes.back()->first );
4364       }
4365       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4366         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4367         std::advance( v, volNb );
4368         // find indices of free faces of a volume and their source edges
4369         list< int > freeInd;
4370         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4371         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4372         int iF, nbF = vTool.NbFaces();
4373         for ( iF = 0; iF < nbF; iF ++ ) {
4374           if (vTool.IsFreeFace( iF ) &&
4375               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4376               initNodeSet != faceNodeSet) // except an initial face
4377           {
4378             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4379               continue;
4380             if ( faceNodeSet == initNodeSetNoCenter )
4381               continue;
4382             freeInd.push_back( iF );
4383             // find source edge of a free face iF
4384             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4385             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4386             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4387                                    initNodeSet.begin(), initNodeSet.end(),
4388                                    commonNodes.begin());
4389             if ( (*v)->IsQuadratic() )
4390               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4391             else
4392               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4393 #ifdef _DEBUG_
4394             if ( !srcEdges.back() )
4395             {
4396               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4397                    << iF << " of volume #" << vTool.ID() << endl;
4398             }
4399 #endif
4400           }
4401         }
4402         if ( freeInd.empty() )
4403           continue;
4404
4405         // create faces for all steps;
4406         // if such a face has been already created by sweep of edge,
4407         // assure that its orientation is OK
4408         for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4409           vTool.Set( *v, /*ignoreCentralNodes=*/false );
4410           vTool.SetExternalNormal();
4411           const int nextShift = vTool.IsForward() ? +1 : -1;
4412           list< int >::iterator ind = freeInd.begin();
4413           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4414           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4415           {
4416             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4417             int nbn = vTool.NbFaceNodes( *ind );
4418             const SMDS_MeshElement * f = 0;
4419             if ( nbn == 3 )              ///// triangle
4420             {
4421               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4422               if ( !f ||
4423                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4424               {
4425                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4426                                                      nodes[ 1 ],
4427                                                      nodes[ 1 + nextShift ] };
4428                 if ( f )
4429                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4430                 else
4431                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4432                                                             newOrder[ 2 ] ));
4433               }
4434             }
4435             else if ( nbn == 4 )       ///// quadrangle
4436             {
4437               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4438               if ( !f ||
4439                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4440               {
4441                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4442                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
4443                 if ( f )
4444                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4445                 else
4446                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4447                                                             newOrder[ 2 ], newOrder[ 3 ]));
4448               }
4449             }
4450             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4451             {
4452               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4453               if ( !f ||
4454                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4455               {
4456                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4457                                                      nodes[2],
4458                                                      nodes[2 + 2*nextShift],
4459                                                      nodes[3 - 2*nextShift],
4460                                                      nodes[3],
4461                                                      nodes[3 + 2*nextShift]};
4462                 if ( f )
4463                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4464                 else
4465                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4466                                                             newOrder[ 1 ],
4467                                                             newOrder[ 2 ],
4468                                                             newOrder[ 3 ],
4469                                                             newOrder[ 4 ],
4470                                                             newOrder[ 5 ] ));
4471               }
4472             }
4473             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4474             {
4475               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4476                                    nodes[1], nodes[3], nodes[5], nodes[7] );
4477               if ( !f ||
4478                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4479               {
4480                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4481                                                      nodes[4 - 2*nextShift],
4482                                                      nodes[4],
4483                                                      nodes[4 + 2*nextShift],
4484                                                      nodes[1],
4485                                                      nodes[5 - 2*nextShift],
4486                                                      nodes[5],
4487                                                      nodes[5 + 2*nextShift] };
4488                 if ( f )
4489                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4490                 else
4491                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4492                                                            newOrder[ 2 ], newOrder[ 3 ],
4493                                                            newOrder[ 4 ], newOrder[ 5 ],
4494                                                            newOrder[ 6 ], newOrder[ 7 ]));
4495               }
4496             }
4497             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4498             {
4499               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4500                                       SMDSAbs_Face, /*noMedium=*/false);
4501               if ( !f ||
4502                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4503               {
4504                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
4505                                                      nodes[4 - 2*nextShift],
4506                                                      nodes[4],
4507                                                      nodes[4 + 2*nextShift],
4508                                                      nodes[1],
4509                                                      nodes[5 - 2*nextShift],
4510                                                      nodes[5],
4511                                                      nodes[5 + 2*nextShift],
4512                                                      nodes[8] };
4513                 if ( f )
4514                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4515                 else
4516                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4517                                                            newOrder[ 2 ], newOrder[ 3 ],
4518                                                            newOrder[ 4 ], newOrder[ 5 ],
4519                                                            newOrder[ 6 ], newOrder[ 7 ],
4520                                                            newOrder[ 8 ]));
4521               }
4522             }
4523             else  //////// polygon
4524             {
4525               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
4526               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4527               if ( !f ||
4528                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4529               {
4530                 if ( !vTool.IsForward() )
4531                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4532                 if ( f )
4533                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4534                 else
4535                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4536               }
4537             }
4538
4539             while ( srcElements.Length() < myLastCreatedElems.Length() )
4540               srcElements.Append( *srcEdge );
4541
4542           }  // loop on free faces
4543
4544           // go to the next volume
4545           iVol = 0;
4546           while ( iVol++ < nbVolumesByStep ) v++;
4547
4548         } // loop on steps
4549       } // loop on volumes of one step
4550     } // sweep free links into faces
4551
4552     // Make a ceiling face with a normal external to a volume
4553
4554     // use SMDS_VolumeTool to get a correctly ordered nodes of a ceiling face
4555     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
4556     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4557
4558     if ( iF < 0 && isQuadratic && nbNodes % 2 ) { // remove a central node of biquadratic
4559       aFaceLastNodes.erase( vecNewNodes.back()->second.back() );
4560       iF = lastVol.GetFaceIndex( aFaceLastNodes );
4561     }
4562     if ( iF >= 0 ) {
4563       lastVol.SetExternalNormal();
4564       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4565       int nbn = lastVol.NbFaceNodes( iF );
4566       // we do not use this->AddElement() because nodes are interlaced
4567       vector<const SMDS_MeshNode*> nodeVec( nodes, nodes+nbn );
4568       if ( !hasFreeLinks ||
4569            !aMesh->FindElement( nodeVec, SMDSAbs_Face, /*noMedium=*/false) )
4570       {
4571         if ( nbn == 3 )
4572           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2] ));
4573
4574         else if ( nbn == 4 )
4575           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2], nodes[3]));
4576
4577         else if ( nbn == 6 && isQuadratic )
4578           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4],
4579                                                     nodes[1], nodes[3], nodes[5]));
4580         else if ( nbn == 7 && isQuadratic )
4581           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4],
4582                                                     nodes[1], nodes[3], nodes[5], nodes[6]));
4583         else if ( nbn == 8 && isQuadratic )
4584           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], nodes[6],
4585                                                     nodes[1], nodes[3], nodes[5], nodes[7]));
4586         else if ( nbn == 9 && isQuadratic )
4587           myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], nodes[6],
4588                                                     nodes[1], nodes[3], nodes[5], nodes[7],
4589                                                     nodes[8]));
4590         else
4591           myLastCreatedElems.Append(aMesh->AddPolygonalFace( nodeVec ));
4592
4593         while ( srcElements.Length() < myLastCreatedElems.Length() )
4594           srcElements.Append( elem );
4595       }
4596     }
4597   } // loop on swept elements
4598 }
4599
4600 //=======================================================================
4601 //function : RotationSweep
4602 //purpose  :
4603 //=======================================================================
4604
4605 SMESH_MeshEditor::PGroupIDs
4606 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4607                                 const gp_Ax1&      theAxis,
4608                                 const double       theAngle,
4609                                 const int          theNbSteps,
4610                                 const double       theTol,
4611                                 const bool         theMakeGroups,
4612                                 const bool         theMakeWalls)
4613 {
4614   myLastCreatedElems.Clear();
4615   myLastCreatedNodes.Clear();
4616
4617   // source elements for each generated one
4618   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4619
4620   MESSAGE( "RotationSweep()");
4621   gp_Trsf aTrsf;
4622   aTrsf.SetRotation( theAxis, theAngle );
4623   gp_Trsf aTrsf2;
4624   aTrsf2.SetRotation( theAxis, theAngle/2. );
4625
4626   gp_Lin aLine( theAxis );
4627   double aSqTol = theTol * theTol;
4628
4629   SMESHDS_Mesh* aMesh = GetMeshDS();
4630
4631   TNodeOfNodeListMap mapNewNodes;
4632   TElemOfVecOfNnlmiMap mapElemNewNodes;
4633   TElemOfElemListMap newElemsMap;
4634
4635   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4636                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4637                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4638   // loop on theElems
4639   TIDSortedElemSet::iterator itElem;
4640   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4641     const SMDS_MeshElement* elem = *itElem;
4642     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4643       continue;
4644     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4645     newNodesItVec.reserve( elem->NbNodes() );
4646
4647     // loop on elem nodes
4648     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4649     while ( itN->more() )
4650     {
4651       // check if a node has been already sweeped
4652       const SMDS_MeshNode* node = cast2Node( itN->next() );
4653
4654       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4655       double coord[3];
4656       aXYZ.Coord( coord[0], coord[1], coord[2] );
4657       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4658
4659       TNodeOfNodeListMapItr nIt =
4660         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4661       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4662       if ( listNewNodes.empty() )
4663       {
4664         // check if we are to create medium nodes between corner ones
4665         bool needMediumNodes = false;
4666         if ( isQuadraticMesh )
4667         {
4668           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4669           while (it->more() && !needMediumNodes )
4670           {
4671             const SMDS_MeshElement* invElem = it->next();
4672             if ( invElem != elem && !theElems.count( invElem )) continue;
4673             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4674             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4675               needMediumNodes = true;
4676           }
4677         }
4678
4679         // make new nodes
4680         const SMDS_MeshNode * newNode = node;
4681         for ( int i = 0; i < theNbSteps; i++ ) {
4682           if ( !isOnAxis ) {
4683             if ( needMediumNodes )  // create a medium node
4684             {
4685               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4686               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4687               myLastCreatedNodes.Append(newNode);
4688               srcNodes.Append( node );
4689               listNewNodes.push_back( newNode );
4690               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4691             }
4692             else {
4693               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4694             }
4695             // create a corner node
4696             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4697             myLastCreatedNodes.Append(newNode);
4698             srcNodes.Append( node );
4699             listNewNodes.push_back( newNode );
4700           }
4701           else {
4702             listNewNodes.push_back( newNode );
4703             // if ( needMediumNodes )
4704             //   listNewNodes.push_back( newNode );
4705           }
4706         }
4707       }
4708       newNodesItVec.push_back( nIt );
4709     }
4710     // make new elements
4711     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4712   }
4713
4714   if ( theMakeWalls )
4715     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4716
4717   PGroupIDs newGroupIDs;
4718   if ( theMakeGroups )
4719     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4720
4721   return newGroupIDs;
4722 }
4723
4724
4725 //=======================================================================
4726 //function : CreateNode
4727 //purpose  :
4728 //=======================================================================
4729 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4730                                                   const double y,
4731                                                   const double z,
4732                                                   const double tolnode,
4733                                                   SMESH_SequenceOfNode& aNodes)
4734 {
4735   // myLastCreatedElems.Clear();
4736   // myLastCreatedNodes.Clear();
4737
4738   gp_Pnt P1(x,y,z);
4739   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4740
4741   // try to search in sequence of existing nodes
4742   // if aNodes.Length()>0 we 'nave to use given sequence
4743   // else - use all nodes of mesh
4744   if(aNodes.Length()>0) {
4745     int i;
4746     for(i=1; i<=aNodes.Length(); i++) {
4747       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4748       if(P1.Distance(P2)<tolnode)
4749         return aNodes.Value(i);
4750     }
4751   }
4752   else {
4753     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4754     while(itn->more()) {
4755       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4756       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4757       if(P1.Distance(P2)<tolnode)
4758         return aN;
4759     }
4760   }
4761
4762   // create new node and return it
4763   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4764   //myLastCreatedNodes.Append(NewNode);
4765   return NewNode;
4766 }
4767
4768
4769 //=======================================================================
4770 //function : ExtrusionSweep
4771 //purpose  :
4772 //=======================================================================
4773
4774 SMESH_MeshEditor::PGroupIDs
4775 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4776                                   const gp_Vec&       theStep,
4777                                   const int           theNbSteps,
4778                                   TElemOfElemListMap& newElemsMap,
4779                                   const bool          theMakeGroups,
4780                                   const int           theFlags,
4781                                   const double        theTolerance)
4782 {
4783   ExtrusParam aParams;
4784   aParams.myDir = gp_Dir(theStep);
4785   aParams.myNodes.Clear();
4786   aParams.mySteps = new TColStd_HSequenceOfReal;
4787   int i;
4788   for(i=1; i<=theNbSteps; i++)
4789     aParams.mySteps->Append(theStep.Magnitude());
4790
4791   return
4792     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4793 }
4794
4795
4796 //=======================================================================
4797 //function : ExtrusionSweep
4798 //purpose  :
4799 //=======================================================================
4800
4801 SMESH_MeshEditor::PGroupIDs
4802 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4803                                   ExtrusParam&        theParams,
4804                                   TElemOfElemListMap& newElemsMap,
4805                                   const bool          theMakeGroups,
4806                                   const int           theFlags,
4807                                   const double        theTolerance)
4808 {
4809   myLastCreatedElems.Clear();
4810   myLastCreatedNodes.Clear();
4811
4812   // source elements for each generated one
4813   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4814
4815   SMESHDS_Mesh* aMesh = GetMeshDS();
4816
4817   int nbsteps = theParams.mySteps->Length();
4818
4819   TNodeOfNodeListMap mapNewNodes;
4820   //TNodeOfNodeVecMap mapNewNodes;
4821   TElemOfVecOfNnlmiMap mapElemNewNodes;
4822   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4823
4824   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4825                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4826                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4827   // loop on theElems
4828   TIDSortedElemSet::iterator itElem;
4829   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4830     // check element type
4831     const SMDS_MeshElement* elem = *itElem;
4832     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4833       continue;
4834
4835     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4836     newNodesItVec.reserve( elem->NbNodes() );
4837
4838     // loop on elem nodes
4839     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4840     while ( itN->more() )
4841     {
4842       // check if a node has been already sweeped
4843       const SMDS_MeshNode* node = cast2Node( itN->next() );
4844       TNodeOfNodeListMap::iterator nIt =
4845         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4846       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4847       if ( listNewNodes.empty() )
4848       {
4849         // make new nodes
4850
4851         // check if we are to create medium nodes between corner ones
4852         bool needMediumNodes = false;
4853         if ( isQuadraticMesh )
4854         {
4855           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4856           while (it->more() && !needMediumNodes )
4857           {
4858             const SMDS_MeshElement* invElem = it->next();
4859             if ( invElem != elem && !theElems.count( invElem )) continue;
4860             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4861             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4862               needMediumNodes = true;
4863           }
4864         }
4865
4866         double coord[] = { node->X(), node->Y(), node->Z() };
4867         for ( int i = 0; i < nbsteps; i++ )
4868         {
4869           if ( needMediumNodes ) // create a medium node
4870           {
4871             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4872             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4873             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4874             if( theFlags & EXTRUSION_FLAG_SEW ) {
4875               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4876                                                          theTolerance, theParams.myNodes);
4877               listNewNodes.push_back( newNode );
4878             }
4879             else {
4880               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4881               myLastCreatedNodes.Append(newNode);
4882               srcNodes.Append( node );
4883               listNewNodes.push_back( newNode );
4884             }
4885           }
4886           // create a corner node
4887           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4888           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4889           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4890           if( theFlags & EXTRUSION_FLAG_SEW ) {
4891             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4892                                                        theTolerance, theParams.myNodes);
4893             listNewNodes.push_back( newNode );
4894           }
4895           else {
4896             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4897             myLastCreatedNodes.Append(newNode);
4898             srcNodes.Append( node );
4899             listNewNodes.push_back( newNode );
4900           }
4901         }
4902       }
4903       newNodesItVec.push_back( nIt );
4904     }
4905     // make new elements
4906     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4907   }
4908
4909   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4910     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4911   }
4912   PGroupIDs newGroupIDs;
4913   if ( theMakeGroups )
4914     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4915
4916   return newGroupIDs;
4917 }
4918
4919 //=======================================================================
4920 //function : ExtrusionAlongTrack
4921 //purpose  :
4922 //=======================================================================
4923 SMESH_MeshEditor::Extrusion_Error
4924 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4925                                        SMESH_subMesh*       theTrack,
4926                                        const SMDS_MeshNode* theN1,
4927                                        const bool           theHasAngles,
4928                                        list<double>&        theAngles,
4929                                        const bool           theLinearVariation,
4930                                        const bool           theHasRefPoint,
4931                                        const gp_Pnt&        theRefPoint,
4932                                        const bool           theMakeGroups)
4933 {
4934   MESSAGE("ExtrusionAlongTrack");
4935   myLastCreatedElems.Clear();
4936   myLastCreatedNodes.Clear();
4937
4938   int aNbE;
4939   std::list<double> aPrms;
4940   TIDSortedElemSet::iterator itElem;
4941
4942   gp_XYZ aGC;
4943   TopoDS_Edge aTrackEdge;
4944   TopoDS_Vertex aV1, aV2;
4945
4946   SMDS_ElemIteratorPtr aItE;
4947   SMDS_NodeIteratorPtr aItN;
4948   SMDSAbs_ElementType aTypeE;
4949
4950   TNodeOfNodeListMap mapNewNodes;
4951
4952   // 1. Check data
4953   aNbE = theElements.size();
4954   // nothing to do
4955   if ( !aNbE )
4956     return EXTR_NO_ELEMENTS;
4957
4958   // 1.1 Track Pattern
4959   ASSERT( theTrack );
4960
4961   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4962
4963   aItE = pSubMeshDS->GetElements();
4964   while ( aItE->more() ) {
4965     const SMDS_MeshElement* pE = aItE->next();
4966     aTypeE = pE->GetType();
4967     // Pattern must contain links only
4968     if ( aTypeE != SMDSAbs_Edge )
4969       return EXTR_PATH_NOT_EDGE;
4970   }
4971
4972   list<SMESH_MeshEditor_PathPoint> fullList;
4973
4974   const TopoDS_Shape& aS = theTrack->GetSubShape();
4975   // Sub-shape for the Pattern must be an Edge or Wire
4976   if( aS.ShapeType() == TopAbs_EDGE ) {
4977     aTrackEdge = TopoDS::Edge( aS );
4978     // the Edge must not be degenerated
4979     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4980       return EXTR_BAD_PATH_SHAPE;
4981     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4982     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4983     const SMDS_MeshNode* aN1 = aItN->next();
4984     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4985     const SMDS_MeshNode* aN2 = aItN->next();
4986     // starting node must be aN1 or aN2
4987     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4988       return EXTR_BAD_STARTING_NODE;
4989     aItN = pSubMeshDS->GetNodes();
4990     while ( aItN->more() ) {
4991       const SMDS_MeshNode* pNode = aItN->next();
4992       const SMDS_EdgePosition* pEPos =
4993         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4994       double aT = pEPos->GetUParameter();
4995       aPrms.push_back( aT );
4996     }
4997     //Extrusion_Error err =
4998     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4999   } else if( aS.ShapeType() == TopAbs_WIRE ) {
5000     list< SMESH_subMesh* > LSM;
5001     TopTools_SequenceOfShape Edges;
5002     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
5003     while(itSM->more()) {
5004       SMESH_subMesh* SM = itSM->next();
5005       LSM.push_back(SM);
5006       const TopoDS_Shape& aS = SM->GetSubShape();
5007       Edges.Append(aS);
5008     }
5009     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5010     int startNid = theN1->GetID();
5011     TColStd_MapOfInteger UsedNums;
5012
5013     int NbEdges = Edges.Length();
5014     int i = 1;
5015     for(; i<=NbEdges; i++) {
5016       int k = 0;
5017       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5018       for(; itLSM!=LSM.end(); itLSM++) {
5019         k++;
5020         if(UsedNums.Contains(k)) continue;
5021         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5022         SMESH_subMesh* locTrack = *itLSM;
5023         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5024         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5025         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5026         const SMDS_MeshNode* aN1 = aItN->next();
5027         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5028         const SMDS_MeshNode* aN2 = aItN->next();
5029         // starting node must be aN1 or aN2
5030         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
5031         // 2. Collect parameters on the track edge
5032         aPrms.clear();
5033         aItN = locMeshDS->GetNodes();
5034         while ( aItN->more() ) {
5035           const SMDS_MeshNode* pNode = aItN->next();
5036           const SMDS_EdgePosition* pEPos =
5037             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5038           double aT = pEPos->GetUParameter();
5039           aPrms.push_back( aT );
5040         }
5041         list<SMESH_MeshEditor_PathPoint> LPP;
5042         //Extrusion_Error err =
5043         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
5044         LLPPs.push_back(LPP);
5045         UsedNums.Add(k);
5046         // update startN for search following egde
5047         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
5048         else startNid = aN1->GetID();
5049         break;
5050       }
5051     }
5052     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5053     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5054     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5055     for(; itPP!=firstList.end(); itPP++) {
5056       fullList.push_back( *itPP );
5057     }
5058     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5059     fullList.pop_back();
5060     itLLPP++;
5061     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5062       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5063       itPP = currList.begin();
5064       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5065       gp_Dir D1 = PP1.Tangent();
5066       gp_Dir D2 = PP2.Tangent();
5067       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5068                            (D1.Z()+D2.Z())/2 ) );
5069       PP1.SetTangent(Dnew);
5070       fullList.push_back(PP1);
5071       itPP++;
5072       for(; itPP!=firstList.end(); itPP++) {
5073         fullList.push_back( *itPP );
5074       }
5075       PP1 = fullList.back();
5076       fullList.pop_back();
5077     }
5078     // if wire not closed
5079     fullList.push_back(PP1);
5080     // else ???
5081   }
5082   else {
5083     return EXTR_BAD_PATH_SHAPE;
5084   }
5085
5086   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5087                           theHasRefPoint, theRefPoint, theMakeGroups);
5088 }
5089
5090
5091 //=======================================================================
5092 //function : ExtrusionAlongTrack
5093 //purpose  :
5094 //=======================================================================
5095 SMESH_MeshEditor::Extrusion_Error
5096 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
5097                                        SMESH_Mesh*          theTrack,
5098                                        const SMDS_MeshNode* theN1,
5099                                        const bool           theHasAngles,
5100                                        list<double>&        theAngles,
5101                                        const bool           theLinearVariation,
5102                                        const bool           theHasRefPoint,
5103                                        const gp_Pnt&        theRefPoint,
5104                                        const bool           theMakeGroups)
5105 {
5106   myLastCreatedElems.Clear();
5107   myLastCreatedNodes.Clear();
5108
5109   int aNbE;
5110   std::list<double> aPrms;
5111   TIDSortedElemSet::iterator itElem;
5112
5113   gp_XYZ aGC;
5114   TopoDS_Edge aTrackEdge;
5115   TopoDS_Vertex aV1, aV2;
5116
5117   SMDS_ElemIteratorPtr aItE;
5118   SMDS_NodeIteratorPtr aItN;
5119   SMDSAbs_ElementType aTypeE;
5120
5121   TNodeOfNodeListMap mapNewNodes;
5122
5123   // 1. Check data
5124   aNbE = theElements.size();
5125   // nothing to do
5126   if ( !aNbE )
5127     return EXTR_NO_ELEMENTS;
5128
5129   // 1.1 Track Pattern
5130   ASSERT( theTrack );
5131
5132   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
5133
5134   aItE = pMeshDS->elementsIterator();
5135   while ( aItE->more() ) {
5136     const SMDS_MeshElement* pE = aItE->next();
5137     aTypeE = pE->GetType();
5138     // Pattern must contain links only
5139     if ( aTypeE != SMDSAbs_Edge )
5140       return EXTR_PATH_NOT_EDGE;
5141   }
5142
5143   list<SMESH_MeshEditor_PathPoint> fullList;
5144
5145   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
5146
5147   if( aS == SMESH_Mesh::PseudoShape() ) {
5148     //Mesh without shape
5149     const SMDS_MeshNode* currentNode = NULL;
5150     const SMDS_MeshNode* prevNode = theN1;
5151     std::vector<const SMDS_MeshNode*> aNodesList;
5152     aNodesList.push_back(theN1);
5153     int nbEdges = 0, conn=0;
5154     const SMDS_MeshElement* prevElem = NULL;
5155     const SMDS_MeshElement* currentElem = NULL;
5156     int totalNbEdges = theTrack->NbEdges();
5157     SMDS_ElemIteratorPtr nIt;
5158
5159     //check start node
5160     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
5161       return EXTR_BAD_STARTING_NODE;
5162     }
5163
5164     conn = nbEdgeConnectivity(theN1);
5165     if(conn > 2)
5166       return EXTR_PATH_NOT_EDGE;
5167
5168     aItE = theN1->GetInverseElementIterator();
5169     prevElem = aItE->next();
5170     currentElem = prevElem;
5171     //Get all nodes
5172     if(totalNbEdges == 1 ) {
5173       nIt = currentElem->nodesIterator();
5174       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5175       if(currentNode == prevNode)
5176         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5177       aNodesList.push_back(currentNode);
5178     } else {
5179       nIt = currentElem->nodesIterator();
5180       while( nIt->more() ) {
5181         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5182         if(currentNode == prevNode)
5183           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5184         aNodesList.push_back(currentNode);
5185
5186         //case of the closed mesh
5187         if(currentNode == theN1) {
5188           nbEdges++;
5189           break;
5190         }
5191
5192         conn = nbEdgeConnectivity(currentNode);
5193         if(conn > 2) {
5194           return EXTR_PATH_NOT_EDGE;
5195         }else if( conn == 1 && nbEdges > 0 ) {
5196           //End of the path
5197           nbEdges++;
5198           break;
5199         }else {
5200           prevNode = currentNode;
5201           aItE = currentNode->GetInverseElementIterator();
5202           currentElem = aItE->next();
5203           if( currentElem  == prevElem)
5204             currentElem = aItE->next();
5205           nIt = currentElem->nodesIterator();
5206           prevElem = currentElem;
5207           nbEdges++;
5208         }
5209       }
5210     }
5211
5212     if(nbEdges != totalNbEdges)
5213       return EXTR_PATH_NOT_EDGE;
5214
5215     TopTools_SequenceOfShape Edges;
5216     double x1,x2,y1,y2,z1,z2;
5217     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5218     int startNid = theN1->GetID();
5219     for(int i = 1; i < aNodesList.size(); i++) {
5220       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
5221       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
5222       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
5223       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));
5224       list<SMESH_MeshEditor_PathPoint> LPP;
5225       aPrms.clear();
5226       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
5227       LLPPs.push_back(LPP);
5228       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
5229       else startNid = aNodesList[i-1]->GetID();
5230
5231     }
5232
5233     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5234     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5235     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5236     for(; itPP!=firstList.end(); itPP++) {
5237       fullList.push_back( *itPP );
5238     }
5239
5240     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5241     SMESH_MeshEditor_PathPoint PP2;
5242     fullList.pop_back();
5243     itLLPP++;
5244     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5245       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5246       itPP = currList.begin();
5247       PP2 = currList.front();
5248       gp_Dir D1 = PP1.Tangent();
5249       gp_Dir D2 = PP2.Tangent();
5250       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5251                            (D1.Z()+D2.Z())/2 ) );
5252       PP1.SetTangent(Dnew);
5253       fullList.push_back(PP1);
5254       itPP++;
5255       for(; itPP!=currList.end(); itPP++) {
5256         fullList.push_back( *itPP );
5257       }
5258       PP1 = fullList.back();
5259       fullList.pop_back();
5260     }
5261     fullList.push_back(PP1);
5262
5263   } // Sub-shape for the Pattern must be an Edge or Wire
5264   else if( aS.ShapeType() == TopAbs_EDGE ) {
5265     aTrackEdge = TopoDS::Edge( aS );
5266     // the Edge must not be degenerated
5267     if ( BRep_Tool::Degenerated( aTrackEdge ) )
5268       return EXTR_BAD_PATH_SHAPE;
5269     TopExp::Vertices( aTrackEdge, aV1, aV2 );
5270     const SMDS_MeshNode* aN1 = 0;
5271     const SMDS_MeshNode* aN2 = 0;
5272     if ( theTrack->GetSubMesh( aV1 ) && theTrack->GetSubMesh( aV1 )->GetSubMeshDS() ) {
5273       aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
5274       aN1 = aItN->next();
5275     }
5276     if ( theTrack->GetSubMesh( aV2 ) && theTrack->GetSubMesh( aV2 )->GetSubMeshDS() ) {
5277       aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
5278       aN2 = aItN->next();
5279     }
5280     // starting node must be aN1 or aN2
5281     if ( !( aN1 == theN1 || aN2 == theN1 ) )
5282       return EXTR_BAD_STARTING_NODE;
5283     aItN = pMeshDS->nodesIterator();
5284     while ( aItN->more() ) {
5285       const SMDS_MeshNode* pNode = aItN->next();
5286       if( pNode==aN1 || pNode==aN2 ) continue;
5287       const SMDS_EdgePosition* pEPos =
5288         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5289       double aT = pEPos->GetUParameter();
5290       aPrms.push_back( aT );
5291     }
5292     //Extrusion_Error err =
5293     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5294   }
5295   else if( aS.ShapeType() == TopAbs_WIRE ) {
5296     list< SMESH_subMesh* > LSM;
5297     TopTools_SequenceOfShape Edges;
5298     TopExp_Explorer eExp(aS, TopAbs_EDGE);
5299     for(; eExp.More(); eExp.Next()) {
5300       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5301       if( BRep_Tool::Degenerated(E) ) continue;
5302       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5303       if(SM) {
5304         LSM.push_back(SM);
5305         Edges.Append(E);
5306       }
5307     }
5308     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5309     TopoDS_Vertex aVprev;
5310     TColStd_MapOfInteger UsedNums;
5311     int NbEdges = Edges.Length();
5312     int i = 1;
5313     for(; i<=NbEdges; i++) {
5314       int k = 0;
5315       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5316       for(; itLSM!=LSM.end(); itLSM++) {
5317         k++;
5318         if(UsedNums.Contains(k)) continue;
5319         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5320         SMESH_subMesh* locTrack = *itLSM;
5321         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5322         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5323         bool aN1isOK = false, aN2isOK = false;
5324         if ( aVprev.IsNull() ) {
5325           // if previous vertex is not yet defined, it means that we in the beginning of wire
5326           // and we have to find initial vertex corresponding to starting node theN1
5327           const SMDS_MeshNode* aN1 = 0;
5328           const SMDS_MeshNode* aN2 = 0;
5329
5330           if ( locTrack->GetFather()->GetSubMesh(aV1) && locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS() ) {
5331             aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5332             aN1 = aItN->next();
5333           }
5334           if ( locTrack->GetFather()->GetSubMesh(aV2) && locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS() ) {
5335             aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5336             aN2 = aItN->next();
5337           }
5338           // starting node must be aN1 or aN2
5339           aN1isOK = ( aN1 && aN1 == theN1 );
5340           aN2isOK = ( aN2 && aN2 == theN1 );
5341         }
5342         else {
5343           // we have specified ending vertex of the previous edge on the previous iteration
5344           // and we have just to check that it corresponds to any vertex in current segment
5345           aN1isOK = aVprev.IsSame( aV1 );
5346           aN2isOK = aVprev.IsSame( aV2 );
5347         }
5348         if ( !aN1isOK && !aN2isOK ) continue;
5349         // 2. Collect parameters on the track edge
5350         aPrms.clear();
5351         aItN = locMeshDS->GetNodes();
5352         while ( aItN->more() ) {
5353           const SMDS_MeshNode*     pNode = aItN->next();
5354           const SMDS_EdgePosition* pEPos =
5355             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5356           double aT = pEPos->GetUParameter();
5357           aPrms.push_back( aT );
5358         }
5359         list<SMESH_MeshEditor_PathPoint> LPP;
5360         //Extrusion_Error err =
5361         MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
5362         LLPPs.push_back(LPP);
5363         UsedNums.Add(k);
5364         // update startN for search following egde
5365         if ( aN1isOK ) aVprev = aV2;
5366         else           aVprev = aV1;
5367         break;
5368       }
5369     }
5370     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5371     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5372     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5373     for(; itPP!=firstList.end(); itPP++) {
5374       fullList.push_back( *itPP );
5375     }
5376     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5377     fullList.pop_back();
5378     itLLPP++;
5379     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5380       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5381       itPP = currList.begin();
5382       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5383       gp_Dir D1 = PP1.Tangent();
5384       gp_Dir D2 = PP2.Tangent();
5385       gp_Dir Dnew( ( D1.XYZ() + D2.XYZ() ) / 2 );
5386       PP1.SetTangent(Dnew);
5387       fullList.push_back(PP1);
5388       itPP++;
5389       for(; itPP!=currList.end(); itPP++) {
5390         fullList.push_back( *itPP );
5391       }
5392       PP1 = fullList.back();
5393       fullList.pop_back();
5394     }
5395     // if wire not closed
5396     fullList.push_back(PP1);
5397     // else ???
5398   }
5399   else {
5400     return EXTR_BAD_PATH_SHAPE;
5401   }
5402
5403   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5404                           theHasRefPoint, theRefPoint, theMakeGroups);
5405 }
5406
5407
5408 //=======================================================================
5409 //function : MakeEdgePathPoints
5410 //purpose  : auxilary for ExtrusionAlongTrack
5411 //=======================================================================
5412 SMESH_MeshEditor::Extrusion_Error
5413 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5414                                      const TopoDS_Edge& aTrackEdge,
5415                                      bool FirstIsStart,
5416                                      list<SMESH_MeshEditor_PathPoint>& LPP)
5417 {
5418   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5419   aTolVec=1.e-7;
5420   aTolVec2=aTolVec*aTolVec;
5421   double aT1, aT2;
5422   TopoDS_Vertex aV1, aV2;
5423   TopExp::Vertices( aTrackEdge, aV1, aV2 );
5424   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5425   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5426   // 2. Collect parameters on the track edge
5427   aPrms.push_front( aT1 );
5428   aPrms.push_back( aT2 );
5429   // sort parameters
5430   aPrms.sort();
5431   if( FirstIsStart ) {
5432     if ( aT1 > aT2 ) {
5433       aPrms.reverse();
5434     }
5435   }
5436   else {
5437     if ( aT2 > aT1 ) {
5438       aPrms.reverse();
5439     }
5440   }
5441   // 3. Path Points
5442   SMESH_MeshEditor_PathPoint aPP;
5443   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5444   std::list<double>::iterator aItD = aPrms.begin();
5445   for(; aItD != aPrms.end(); ++aItD) {
5446     double aT = *aItD;
5447     gp_Pnt aP3D;
5448     gp_Vec aVec;
5449     aC3D->D1( aT, aP3D, aVec );
5450     aL2 = aVec.SquareMagnitude();
5451     if ( aL2 < aTolVec2 )
5452       return EXTR_CANT_GET_TANGENT;
5453     gp_Dir aTgt( aVec );
5454     aPP.SetPnt( aP3D );
5455     aPP.SetTangent( aTgt );
5456     aPP.SetParameter( aT );
5457     LPP.push_back(aPP);
5458   }
5459   return EXTR_OK;
5460 }
5461
5462
5463 //=======================================================================
5464 //function : MakeExtrElements
5465 //purpose  : auxilary for ExtrusionAlongTrack
5466 //=======================================================================
5467 SMESH_MeshEditor::Extrusion_Error
5468 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5469                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5470                                    const bool theHasAngles,
5471                                    list<double>& theAngles,
5472                                    const bool theLinearVariation,
5473                                    const bool theHasRefPoint,
5474                                    const gp_Pnt& theRefPoint,
5475                                    const bool theMakeGroups)
5476 {
5477   MESSAGE("MakeExtrElements");
5478   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5479   int aNbTP = fullList.size();
5480   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5481   // Angles
5482   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5483     LinearAngleVariation(aNbTP-1, theAngles);
5484   }
5485   vector<double> aAngles( aNbTP );
5486   int j = 0;
5487   for(; j<aNbTP; ++j) {
5488     aAngles[j] = 0.;
5489   }
5490   if ( theHasAngles ) {
5491     double anAngle;;
5492     std::list<double>::iterator aItD = theAngles.begin();
5493     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5494       anAngle = *aItD;
5495       aAngles[j] = anAngle;
5496     }
5497   }
5498   // fill vector of path points with angles
5499   //aPPs.resize(fullList.size());
5500   j = -1;
5501   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5502   for(; itPP!=fullList.end(); itPP++) {
5503     j++;
5504     SMESH_MeshEditor_PathPoint PP = *itPP;
5505     PP.SetAngle(aAngles[j]);
5506     aPPs[j] = PP;
5507   }
5508
5509   TNodeOfNodeListMap mapNewNodes;
5510   TElemOfVecOfNnlmiMap mapElemNewNodes;
5511   TElemOfElemListMap newElemsMap;
5512   TIDSortedElemSet::iterator itElem;
5513   double aX, aY, aZ;
5514   int aNb;
5515   SMDSAbs_ElementType aTypeE;
5516   // source elements for each generated one
5517   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5518
5519   // 3. Center of rotation aV0
5520   gp_Pnt aV0 = theRefPoint;
5521   gp_XYZ aGC;
5522   if ( !theHasRefPoint ) {
5523     aNb = 0;
5524     aGC.SetCoord( 0.,0.,0. );
5525
5526     itElem = theElements.begin();
5527     for ( ; itElem != theElements.end(); itElem++ ) {
5528       const SMDS_MeshElement* elem = *itElem;
5529
5530       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5531       while ( itN->more() ) {
5532         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5533         aX = node->X();
5534         aY = node->Y();
5535         aZ = node->Z();
5536
5537         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5538           list<const SMDS_MeshNode*> aLNx;
5539           mapNewNodes[node] = aLNx;
5540           //
5541           gp_XYZ aXYZ( aX, aY, aZ );
5542           aGC += aXYZ;
5543           ++aNb;
5544         }
5545       }
5546     }
5547     aGC /= aNb;
5548     aV0.SetXYZ( aGC );
5549   } // if (!theHasRefPoint) {
5550   mapNewNodes.clear();
5551
5552   // 4. Processing the elements
5553   SMESHDS_Mesh* aMesh = GetMeshDS();
5554
5555   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5556     // check element type
5557     const SMDS_MeshElement* elem = *itElem;
5558     aTypeE = elem->GetType();
5559     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5560       continue;
5561
5562     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5563     newNodesItVec.reserve( elem->NbNodes() );
5564
5565     // loop on elem nodes
5566     int nodeIndex = -1;
5567     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5568     while ( itN->more() )
5569     {
5570       ++nodeIndex;
5571       // check if a node has been already processed
5572       const SMDS_MeshNode* node =
5573         static_cast<const SMDS_MeshNode*>( itN->next() );
5574       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5575       if ( nIt == mapNewNodes.end() ) {
5576         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5577         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5578
5579         // make new nodes
5580         aX = node->X();  aY = node->Y(); aZ = node->Z();
5581
5582         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5583         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5584         gp_Ax1 anAx1, anAxT1T0;
5585         gp_Dir aDT1x, aDT0x, aDT1T0;
5586
5587         aTolAng=1.e-4;
5588
5589         aV0x = aV0;
5590         aPN0.SetCoord(aX, aY, aZ);
5591
5592         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5593         aP0x = aPP0.Pnt();
5594         aDT0x= aPP0.Tangent();
5595         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5596
5597         for ( j = 1; j < aNbTP; ++j ) {
5598           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5599           aP1x = aPP1.Pnt();
5600           aDT1x = aPP1.Tangent();
5601           aAngle1x = aPP1.Angle();
5602
5603           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5604           // Translation
5605           gp_Vec aV01x( aP0x, aP1x );
5606           aTrsf.SetTranslation( aV01x );
5607
5608           // traslated point
5609           aV1x = aV0x.Transformed( aTrsf );
5610           aPN1 = aPN0.Transformed( aTrsf );
5611
5612           // rotation 1 [ T1,T0 ]
5613           aAngleT1T0=-aDT1x.Angle( aDT0x );
5614           if (fabs(aAngleT1T0) > aTolAng) {
5615             aDT1T0=aDT1x^aDT0x;
5616             anAxT1T0.SetLocation( aV1x );
5617             anAxT1T0.SetDirection( aDT1T0 );
5618             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5619
5620             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5621           }
5622
5623           // rotation 2
5624           if ( theHasAngles ) {
5625             anAx1.SetLocation( aV1x );
5626             anAx1.SetDirection( aDT1x );
5627             aTrsfRot.SetRotation( anAx1, aAngle1x );
5628
5629             aPN1 = aPN1.Transformed( aTrsfRot );
5630           }
5631
5632           // make new node
5633           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5634           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5635             // create additional node
5636             double x = ( aPN1.X() + aPN0.X() )/2.;
5637             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5638             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5639             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5640             myLastCreatedNodes.Append(newNode);
5641             srcNodes.Append( node );
5642             listNewNodes.push_back( newNode );
5643           }
5644           aX = aPN1.X();
5645           aY = aPN1.Y();
5646           aZ = aPN1.Z();
5647           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5648           myLastCreatedNodes.Append(newNode);
5649           srcNodes.Append( node );
5650           listNewNodes.push_back( newNode );
5651
5652           aPN0 = aPN1;
5653           aP0x = aP1x;
5654           aV0x = aV1x;
5655           aDT0x = aDT1x;
5656         }
5657       }
5658
5659       else {
5660         // if current elem is quadratic and current node is not medium
5661         // we have to check - may be it is needed to insert additional nodes
5662         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5663           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5664           if(listNewNodes.size()==aNbTP-1) {
5665             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5666             gp_XYZ P(node->X(), node->Y(), node->Z());
5667             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5668             int i;
5669             for(i=0; i<aNbTP-1; i++) {
5670               const SMDS_MeshNode* N = *it;
5671               double x = ( N->X() + P.X() )/2.;
5672               double y = ( N->Y() + P.Y() )/2.;
5673               double z = ( N->Z() + P.Z() )/2.;
5674               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5675               srcNodes.Append( node );
5676               myLastCreatedNodes.Append(newN);
5677               aNodes[2*i] = newN;
5678               aNodes[2*i+1] = N;
5679               P = gp_XYZ(N->X(),N->Y(),N->Z());
5680             }
5681             listNewNodes.clear();
5682             for(i=0; i<2*(aNbTP-1); i++) {
5683               listNewNodes.push_back(aNodes[i]);
5684             }
5685           }
5686         }
5687       }
5688
5689       newNodesItVec.push_back( nIt );
5690     }
5691     // make new elements
5692     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5693     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5694     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5695   }
5696
5697   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5698
5699   if ( theMakeGroups )
5700     generateGroups( srcNodes, srcElems, "extruded");
5701
5702   return EXTR_OK;
5703 }
5704
5705
5706 //=======================================================================
5707 //function : LinearAngleVariation
5708 //purpose  : auxilary for ExtrusionAlongTrack
5709 //=======================================================================
5710 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5711                                             list<double>& Angles)
5712 {
5713   int nbAngles = Angles.size();
5714   if( nbSteps > nbAngles ) {
5715     vector<double> theAngles(nbAngles);
5716     list<double>::iterator it = Angles.begin();
5717     int i = -1;
5718     for(; it!=Angles.end(); it++) {
5719       i++;
5720       theAngles[i] = (*it);
5721     }
5722     list<double> res;
5723     double rAn2St = double( nbAngles ) / double( nbSteps );
5724     double angPrev = 0, angle;
5725     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5726       double angCur = rAn2St * ( iSt+1 );
5727       double angCurFloor  = floor( angCur );
5728       double angPrevFloor = floor( angPrev );
5729       if ( angPrevFloor == angCurFloor )
5730         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5731       else {
5732         int iP = int( angPrevFloor );
5733         double angPrevCeil = ceil(angPrev);
5734         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5735
5736         int iC = int( angCurFloor );
5737         if ( iC < nbAngles )
5738           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5739
5740         iP = int( angPrevCeil );
5741         while ( iC-- > iP )
5742           angle += theAngles[ iC ];
5743       }
5744       res.push_back(angle);
5745       angPrev = angCur;
5746     }
5747     Angles.clear();
5748     it = res.begin();
5749     for(; it!=res.end(); it++)
5750       Angles.push_back( *it );
5751   }
5752 }
5753
5754
5755 //================================================================================
5756 /*!
5757  * \brief Move or copy theElements applying theTrsf to their nodes
5758  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5759  *  \param theTrsf - transformation to apply
5760  *  \param theCopy - if true, create translated copies of theElems
5761  *  \param theMakeGroups - if true and theCopy, create translated groups
5762  *  \param theTargetMesh - mesh to copy translated elements into
5763  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5764  */
5765 //================================================================================
5766
5767 SMESH_MeshEditor::PGroupIDs
5768 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5769                              const gp_Trsf&     theTrsf,
5770                              const bool         theCopy,
5771                              const bool         theMakeGroups,
5772                              SMESH_Mesh*        theTargetMesh)
5773 {
5774   myLastCreatedElems.Clear();
5775   myLastCreatedNodes.Clear();
5776
5777   bool needReverse = false;
5778   string groupPostfix;
5779   switch ( theTrsf.Form() ) {
5780   case gp_PntMirror:
5781     MESSAGE("gp_PntMirror");
5782     needReverse = true;
5783     groupPostfix = "mirrored";
5784     break;
5785   case gp_Ax1Mirror:
5786     MESSAGE("gp_Ax1Mirror");
5787     groupPostfix = "mirrored";
5788     break;
5789   case gp_Ax2Mirror:
5790     MESSAGE("gp_Ax2Mirror");
5791     needReverse = true;
5792     groupPostfix = "mirrored";
5793     break;
5794   case gp_Rotation:
5795     MESSAGE("gp_Rotation");
5796     groupPostfix = "rotated";
5797     break;
5798   case gp_Translation:
5799     MESSAGE("gp_Translation");
5800     groupPostfix = "translated";
5801     break;
5802   case gp_Scale:
5803     MESSAGE("gp_Scale");
5804     groupPostfix = "scaled";
5805     break;
5806   case gp_CompoundTrsf: // different scale by axis
5807     MESSAGE("gp_CompoundTrsf");
5808     groupPostfix = "scaled";
5809     break;
5810   default:
5811     MESSAGE("default");
5812     needReverse = false;
5813     groupPostfix = "transformed";
5814   }
5815
5816   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5817   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5818   SMESHDS_Mesh* aMesh    = GetMeshDS();
5819
5820
5821   // map old node to new one
5822   TNodeNodeMap nodeMap;
5823
5824   // elements sharing moved nodes; those of them which have all
5825   // nodes mirrored but are not in theElems are to be reversed
5826   TIDSortedElemSet inverseElemSet;
5827
5828   // source elements for each generated one
5829   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5830
5831   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5832   TIDSortedElemSet orphanNode;
5833
5834   if ( theElems.empty() ) // transform the whole mesh
5835   {
5836     // add all elements
5837     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5838     while ( eIt->more() ) theElems.insert( eIt->next() );
5839     // add orphan nodes
5840     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5841     while ( nIt->more() )
5842     {
5843       const SMDS_MeshNode* node = nIt->next();
5844       if ( node->NbInverseElements() == 0)
5845         orphanNode.insert( node );
5846     }
5847   }
5848
5849   // loop on elements to transform nodes : first orphan nodes then elems
5850   TIDSortedElemSet::iterator itElem;
5851   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5852   for (int i=0; i<2; i++)
5853   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5854     const SMDS_MeshElement* elem = *itElem;
5855     if ( !elem )
5856       continue;
5857
5858     // loop on elem nodes
5859     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5860     while ( itN->more() ) {
5861
5862       const SMDS_MeshNode* node = cast2Node( itN->next() );
5863       // check if a node has been already transformed
5864       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5865         nodeMap.insert( make_pair ( node, node ));
5866       if ( !n2n_isnew.second )
5867         continue;
5868
5869       double coord[3];
5870       coord[0] = node->X();
5871       coord[1] = node->Y();
5872       coord[2] = node->Z();
5873       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5874       if ( theTargetMesh ) {
5875         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5876         n2n_isnew.first->second = newNode;
5877         myLastCreatedNodes.Append(newNode);
5878         srcNodes.Append( node );
5879       }
5880       else if ( theCopy ) {
5881         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5882         n2n_isnew.first->second = newNode;
5883         myLastCreatedNodes.Append(newNode);
5884         srcNodes.Append( node );
5885       }
5886       else {
5887         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5888         // node position on shape becomes invalid
5889         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5890           ( SMDS_SpacePosition::originSpacePosition() );
5891       }
5892
5893       // keep inverse elements
5894       if ( !theCopy && !theTargetMesh && needReverse ) {
5895         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5896         while ( invElemIt->more() ) {
5897           const SMDS_MeshElement* iel = invElemIt->next();
5898           inverseElemSet.insert( iel );
5899         }
5900       }
5901     }
5902   }
5903
5904   // either create new elements or reverse mirrored ones
5905   if ( !theCopy && !needReverse && !theTargetMesh )
5906     return PGroupIDs();
5907
5908   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5909   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5910     theElems.insert( *invElemIt );
5911
5912   // Replicate or reverse elements
5913
5914   std::vector<int> iForw;
5915   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5916   {
5917     const SMDS_MeshElement* elem = *itElem;
5918     if ( !elem ) continue;
5919
5920     SMDSAbs_GeometryType geomType = elem->GetGeomType();
5921     int                  nbNodes  = elem->NbNodes();
5922     if ( geomType == SMDSGeom_NONE ) continue; // node
5923
5924     switch ( geomType ) {
5925
5926     case SMDSGeom_POLYGON:  // ---------------------- polygon
5927       {
5928         vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5929         int iNode = 0;
5930         SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5931         while (itN->more()) {
5932           const SMDS_MeshNode* node =
5933             static_cast<const SMDS_MeshNode*>(itN->next());
5934           TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5935           if (nodeMapIt == nodeMap.end())
5936             break; // not all nodes transformed
5937           if (needReverse) {
5938             // reverse mirrored faces and volumes
5939             poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5940           } else {
5941             poly_nodes[iNode] = (*nodeMapIt).second;
5942           }
5943           iNode++;
5944         }
5945         if ( iNode != nbNodes )
5946           continue; // not all nodes transformed
5947
5948         if ( theTargetMesh ) {
5949           myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5950           srcElems.Append( elem );
5951         }
5952         else if ( theCopy ) {
5953           myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5954           srcElems.Append( elem );
5955         }
5956         else {
5957           aMesh->ChangePolygonNodes(elem, poly_nodes);
5958         }
5959       }
5960       break;
5961
5962     case SMDSGeom_POLYHEDRA:  // ------------------ polyhedral volume
5963       {
5964         const SMDS_VtkVolume* aPolyedre =
5965           dynamic_cast<const SMDS_VtkVolume*>( elem );
5966         if (!aPolyedre) {
5967           MESSAGE("Warning: bad volumic element");
5968           continue;
5969         }
5970
5971         vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
5972         vector<int> quantities; quantities.reserve( nbNodes );
5973
5974         bool allTransformed = true;
5975         int nbFaces = aPolyedre->NbFaces();
5976         for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5977           int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5978           for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5979             const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5980             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5981             if (nodeMapIt == nodeMap.end()) {
5982               allTransformed = false; // not all nodes transformed
5983             } else {
5984               poly_nodes.push_back((*nodeMapIt).second);
5985             }
5986             if ( needReverse && allTransformed )
5987               std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
5988           }
5989           quantities.push_back(nbFaceNodes);
5990         }
5991         if ( !allTransformed )
5992           continue; // not all nodes transformed
5993
5994         if ( theTargetMesh ) {
5995           myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5996           srcElems.Append( elem );
5997         }
5998         else if ( theCopy ) {
5999           myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
6000           srcElems.Append( elem );
6001         }
6002         else {
6003           aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6004         }
6005       }
6006       break;
6007
6008     case SMDSGeom_BALL: // -------------------- Ball
6009       {
6010         if ( !theCopy && !theTargetMesh ) continue;
6011
6012         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) );
6013         if (nodeMapIt == nodeMap.end())
6014           continue; // not all nodes transformed
6015
6016         double diameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
6017         if ( theTargetMesh ) {
6018           myLastCreatedElems.Append(aTgtMesh->AddBall( nodeMapIt->second, diameter ));
6019           srcElems.Append( elem );
6020         }
6021         else {
6022           myLastCreatedElems.Append(aMesh->AddBall( nodeMapIt->second, diameter ));
6023           srcElems.Append( elem );
6024         }
6025       }
6026       break;
6027
6028     default: // ----------------------- Regular elements
6029
6030       while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
6031       const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
6032       const std::vector<int>& i = needReverse ? iRev : iForw;
6033
6034       // find transformed nodes
6035       vector<const SMDS_MeshNode*> nodes(nbNodes);
6036       int iNode = 0;
6037       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6038       while ( itN->more() ) {
6039         const SMDS_MeshNode* node =
6040           static_cast<const SMDS_MeshNode*>( itN->next() );
6041         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
6042         if ( nodeMapIt == nodeMap.end() )
6043           break; // not all nodes transformed
6044         nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
6045       }
6046       if ( iNode != nbNodes )
6047         continue; // not all nodes transformed
6048
6049       if ( theTargetMesh ) {
6050         if ( SMDS_MeshElement* copy =
6051              targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
6052           myLastCreatedElems.Append( copy );
6053           srcElems.Append( elem );
6054         }
6055       }
6056       else if ( theCopy ) {
6057         if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
6058           srcElems.Append( elem );
6059       }
6060       else {
6061         // reverse element as it was reversed by transformation
6062         if ( nbNodes > 2 )
6063           aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
6064       }
6065     } // switch ( geomType )
6066
6067   } // loop on elements
6068
6069   PGroupIDs newGroupIDs;
6070
6071   if ( ( theMakeGroups && theCopy ) ||
6072        ( theMakeGroups && theTargetMesh ) )
6073     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
6074
6075   return newGroupIDs;
6076 }
6077
6078 //=======================================================================
6079 /*!
6080  * \brief Create groups of elements made during transformation
6081  * \param nodeGens - nodes making corresponding myLastCreatedNodes
6082  * \param elemGens - elements making corresponding myLastCreatedElems
6083  * \param postfix - to append to names of new groups
6084  */
6085 //=======================================================================
6086
6087 SMESH_MeshEditor::PGroupIDs
6088 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
6089                                  const SMESH_SequenceOfElemPtr& elemGens,
6090                                  const std::string&             postfix,
6091                                  SMESH_Mesh*                    targetMesh)
6092 {
6093   PGroupIDs newGroupIDs( new list<int> );
6094   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6095
6096   // Sort existing groups by types and collect their names
6097
6098   // to store an old group and a generated new ones
6099   using boost::tuple;
6100   using boost::make_tuple;
6101   typedef tuple< SMESHDS_GroupBase*, SMESHDS_Group*, SMESHDS_Group* > TOldNewGroup;
6102   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6103   vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups
6104   // group names
6105   set< string > groupNames;
6106
6107   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6108   if ( !groupIt->more() ) return newGroupIDs;
6109
6110   int newGroupID = mesh->GetGroupIds().back()+1;
6111   while ( groupIt->more() )
6112   {
6113     SMESH_Group * group = groupIt->next();
6114     if ( !group ) continue;
6115     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6116     if ( !groupDS || groupDS->IsEmpty() ) continue;
6117     groupNames.insert    ( group->GetName() );
6118     groupDS->SetStoreName( group->GetName() );
6119     const SMDSAbs_ElementType type = groupDS->GetType();
6120     SMESHDS_Group* newGroup    = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
6121     SMESHDS_Group* newTopGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
6122     groupsByType[ type ].push_back( make_tuple( groupDS, newGroup, newTopGroup ));
6123     orderedOldNewGroups.push_back( & groupsByType[ type ].back() );
6124   }
6125
6126   // Loop on nodes and elements to add them in new groups
6127
6128   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6129   {
6130     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6131     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6132     if ( gens.Length() != elems.Length() )
6133       throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args");
6134
6135     // loop on created elements
6136     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6137     {
6138       const SMDS_MeshElement* sourceElem = gens( iElem );
6139       if ( !sourceElem ) {
6140         MESSAGE("generateGroups(): NULL source element");
6141         continue;
6142       }
6143       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6144       if ( groupsOldNew.empty() ) { // no groups of this type at all
6145         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6146           ++iElem; // skip all elements made by sourceElem
6147         continue;
6148       }
6149       // collect all elements made by the iElem-th sourceElem
6150       list< const SMDS_MeshElement* > resultElems;
6151       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6152         if ( resElem != sourceElem )
6153           resultElems.push_back( resElem );
6154       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6155         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6156           if ( resElem != sourceElem )
6157             resultElems.push_back( resElem );
6158
6159       // there must be a top element
6160       const SMDS_MeshElement* topElem = 0;
6161       if ( isNodes )
6162       {
6163         topElem = resultElems.back();
6164         resultElems.pop_back();
6165       }
6166       else
6167       {
6168         list< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin();
6169         for ( ; resElemIt != resultElems.rend() ; ++resElemIt )
6170           if ( (*resElemIt)->GetType() == sourceElem->GetType() )
6171           {
6172             topElem = *resElemIt;
6173             resultElems.erase( --(resElemIt.base()) ); // erase *resElemIt
6174             break;
6175           }
6176       }
6177
6178       // add resultElems to groups originted from ones the sourceElem belongs to
6179       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6180       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6181       {
6182         SMESHDS_GroupBase* oldGroup = gOldNew->get<0>();
6183         if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup
6184         {
6185           // fill in a new group
6186           SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup();
6187           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6188           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6189             newGroup.Add( *resElemIt );
6190
6191           // fill a "top" group
6192           if ( topElem )
6193           {
6194             SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup();
6195             newTopGroup.Add( topElem );
6196           }
6197         }
6198       }
6199     } // loop on created elements
6200   }// loop on nodes and elements
6201
6202   // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups
6203
6204   list<int> topGrouIds;
6205   for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i )
6206   {
6207     SMESHDS_GroupBase* oldGroupDS =   orderedOldNewGroups[i]->get<0>();
6208     SMESHDS_Group*   newGroups[2] = { orderedOldNewGroups[i]->get<1>(),
6209                                       orderedOldNewGroups[i]->get<2>() };
6210     const int nbNewGroups = !newGroups[0]->IsEmpty() + !newGroups[1]->IsEmpty();
6211     for ( int is2nd = 0; is2nd < 2; ++is2nd )
6212     {
6213       SMESHDS_Group* newGroupDS = newGroups[ is2nd ];
6214       if ( newGroupDS->IsEmpty() )
6215       {
6216         mesh->GetMeshDS()->RemoveGroup( newGroupDS );
6217       }
6218       else
6219       {
6220         // set group type
6221         newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
6222
6223         // make a name
6224         const bool isTop = ( nbNewGroups == 2 &&
6225                              newGroupDS->GetType() == oldGroupDS->GetType() &&
6226                              is2nd );
6227
6228         string name = oldGroupDS->GetStoreName();
6229         if ( !targetMesh ) {
6230           string suffix = ( isTop ? "top": postfix.c_str() );
6231           name += "_";
6232           name += suffix;
6233           int nb = 1;
6234           while ( !groupNames.insert( name ).second ) // name exists
6235             name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << suffix << "_" << nb++;
6236         }
6237         else if ( isTop ) {
6238           name += "_top";
6239         }
6240         newGroupDS->SetStoreName( name.c_str() );
6241
6242         // make a SMESH_Groups
6243         mesh->AddGroup( newGroupDS );
6244         if ( isTop )
6245           topGrouIds.push_back( newGroupDS->GetID() );
6246         else
6247           newGroupIDs->push_back( newGroupDS->GetID() );
6248       }
6249     }
6250   }
6251   newGroupIDs->splice( newGroupIDs->end(), topGrouIds );
6252
6253   return newGroupIDs;
6254 }
6255
6256 //================================================================================
6257 /*!
6258  * \brief Return list of group of nodes close to each other within theTolerance
6259  *        Search among theNodes or in the whole mesh if theNodes is empty using
6260  *        an Octree algorithm
6261  */
6262 //================================================================================
6263
6264 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6265                                             const double         theTolerance,
6266                                             TListOfListOfNodes & theGroupsOfNodes)
6267 {
6268   myLastCreatedElems.Clear();
6269   myLastCreatedNodes.Clear();
6270
6271   if ( theNodes.empty() )
6272   { // get all nodes in the mesh
6273     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6274     while ( nIt->more() )
6275       theNodes.insert( theNodes.end(),nIt->next());
6276   }
6277
6278   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6279 }
6280
6281 //=======================================================================
6282 //function : SimplifyFace
6283 //purpose  :
6284 //=======================================================================
6285
6286 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *>& faceNodes,
6287                                     vector<const SMDS_MeshNode *>&       poly_nodes,
6288                                     vector<int>&                         quantities) const
6289 {
6290   int nbNodes = faceNodes.size();
6291
6292   if (nbNodes < 3)
6293     return 0;
6294
6295   set<const SMDS_MeshNode*> nodeSet;
6296
6297   // get simple seq of nodes
6298   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6299   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6300   int iSimple = 0, nbUnique = 0;
6301
6302   simpleNodes[iSimple++] = faceNodes[0];
6303   nbUnique++;
6304   for (int iCur = 1; iCur < nbNodes; iCur++) {
6305     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6306       simpleNodes[iSimple++] = faceNodes[iCur];
6307       if (nodeSet.insert( faceNodes[iCur] ).second)
6308         nbUnique++;
6309     }
6310   }
6311   int nbSimple = iSimple;
6312   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6313     nbSimple--;
6314     iSimple--;
6315   }
6316
6317   if (nbUnique < 3)
6318     return 0;
6319
6320   // separate loops
6321   int nbNew = 0;
6322   bool foundLoop = (nbSimple > nbUnique);
6323   while (foundLoop) {
6324     foundLoop = false;
6325     set<const SMDS_MeshNode*> loopSet;
6326     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6327       const SMDS_MeshNode* n = simpleNodes[iSimple];
6328       if (!loopSet.insert( n ).second) {
6329         foundLoop = true;
6330
6331         // separate loop
6332         int iC = 0, curLast = iSimple;
6333         for (; iC < curLast; iC++) {
6334           if (simpleNodes[iC] == n) break;
6335         }
6336         int loopLen = curLast - iC;
6337         if (loopLen > 2) {
6338           // create sub-element
6339           nbNew++;
6340           quantities.push_back(loopLen);
6341           for (; iC < curLast; iC++) {
6342             poly_nodes.push_back(simpleNodes[iC]);
6343           }
6344         }
6345         // shift the rest nodes (place from the first loop position)
6346         for (iC = curLast + 1; iC < nbSimple; iC++) {
6347           simpleNodes[iC - loopLen] = simpleNodes[iC];
6348         }
6349         nbSimple -= loopLen;
6350         iSimple -= loopLen;
6351       }
6352     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6353   } // while (foundLoop)
6354
6355   if (iSimple > 2) {
6356     nbNew++;
6357     quantities.push_back(iSimple);
6358     for (int i = 0; i < iSimple; i++)
6359       poly_nodes.push_back(simpleNodes[i]);
6360   }
6361
6362   return nbNew;
6363 }
6364
6365 //=======================================================================
6366 //function : MergeNodes
6367 //purpose  : In each group, the cdr of nodes are substituted by the first one
6368 //           in all elements.
6369 //=======================================================================
6370
6371 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6372 {
6373   MESSAGE("MergeNodes");
6374   myLastCreatedElems.Clear();
6375   myLastCreatedNodes.Clear();
6376
6377   SMESHDS_Mesh* aMesh = GetMeshDS();
6378
6379   TNodeNodeMap nodeNodeMap; // node to replace - new node
6380   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6381   list< int > rmElemIds, rmNodeIds;
6382
6383   // Fill nodeNodeMap and elems
6384
6385   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6386   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6387     list<const SMDS_MeshNode*>& nodes = *grIt;
6388     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6389     const SMDS_MeshNode* nToKeep = *nIt;
6390     //MESSAGE("node to keep " << nToKeep->GetID());
6391     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6392       const SMDS_MeshNode* nToRemove = *nIt;
6393       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6394       if ( nToRemove != nToKeep ) {
6395         //MESSAGE("  node to remove " << nToRemove->GetID());
6396         rmNodeIds.push_back( nToRemove->GetID() );
6397         AddToSameGroups( nToKeep, nToRemove, aMesh );
6398         // set _alwaysComputed to a sub-mesh of VERTEX to enable mesh computing
6399         // after MergeNodes() w/o creating node in place of merged ones.
6400         const SMDS_PositionPtr& pos = nToRemove->GetPosition();
6401         if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX )
6402           if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() ))
6403             sm->SetIsAlwaysComputed( true );
6404       }
6405
6406       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6407       while ( invElemIt->more() ) {
6408         const SMDS_MeshElement* elem = invElemIt->next();
6409         elems.insert(elem);
6410       }
6411     }
6412   }
6413   // Change element nodes or remove an element
6414
6415   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6416   for ( ; eIt != elems.end(); eIt++ ) {
6417     const SMDS_MeshElement* elem = *eIt;
6418     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
6419     int nbNodes = elem->NbNodes();
6420     int aShapeId = FindShape( elem );
6421
6422     set<const SMDS_MeshNode*> nodeSet;
6423     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6424     int iUnique = 0, iCur = 0, nbRepl = 0;
6425     vector<int> iRepl( nbNodes );
6426
6427     // get new seq of nodes
6428     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6429     while ( itN->more() ) {
6430       const SMDS_MeshNode* n =
6431         static_cast<const SMDS_MeshNode*>( itN->next() );
6432
6433       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6434       if ( nnIt != nodeNodeMap.end() ) { // n sticks
6435         n = (*nnIt).second;
6436         // BUG 0020185: begin
6437         {
6438           bool stopRecur = false;
6439           set<const SMDS_MeshNode*> nodesRecur;
6440           nodesRecur.insert(n);
6441           while (!stopRecur) {
6442             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6443             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6444               n = (*nnIt_i).second;
6445               if (!nodesRecur.insert(n).second) {
6446                 // error: recursive dependancy
6447                 stopRecur = true;
6448               }
6449             }
6450             else
6451               stopRecur = true;
6452           }
6453         }
6454         // BUG 0020185: end
6455       }
6456       curNodes[ iCur ] = n;
6457       bool isUnique = nodeSet.insert( n ).second;
6458       if ( isUnique )
6459         uniqueNodes[ iUnique++ ] = n;
6460       else
6461         iRepl[ nbRepl++ ] = iCur;
6462       iCur++;
6463     }
6464
6465     // Analyse element topology after replacement
6466
6467     bool isOk = true;
6468     int nbUniqueNodes = nodeSet.size();
6469     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
6470     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6471       // Polygons and Polyhedral volumes
6472       if (elem->IsPoly()) {
6473
6474         if (elem->GetType() == SMDSAbs_Face) {
6475           // Polygon
6476           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6477           int inode = 0;
6478           for (; inode < nbNodes; inode++) {
6479             face_nodes[inode] = curNodes[inode];
6480           }
6481
6482           vector<const SMDS_MeshNode *> polygons_nodes;
6483           vector<int> quantities;
6484           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6485           if (nbNew > 0) {
6486             inode = 0;
6487             for (int iface = 0; iface < nbNew; iface++) {
6488               int nbNodes = quantities[iface];
6489               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6490               for (int ii = 0; ii < nbNodes; ii++, inode++) {
6491                 poly_nodes[ii] = polygons_nodes[inode];
6492               }
6493               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6494               myLastCreatedElems.Append(newElem);
6495               if (aShapeId)
6496                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6497             }
6498
6499             MESSAGE("ChangeElementNodes MergeNodes Polygon");
6500             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6501             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
6502             int quid =0;
6503             if (nbNew > 0) quid = nbNew - 1;
6504             vector<int> newquant(quantities.begin()+quid, quantities.end());
6505             const SMDS_MeshElement* newElem = 0;
6506             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
6507             myLastCreatedElems.Append(newElem);
6508             if ( aShapeId && newElem )
6509               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6510             rmElemIds.push_back(elem->GetID());
6511           }
6512           else {
6513             rmElemIds.push_back(elem->GetID());
6514           }
6515
6516         }
6517         else if (elem->GetType() == SMDSAbs_Volume) {
6518           // Polyhedral volume
6519           if (nbUniqueNodes < 4) {
6520             rmElemIds.push_back(elem->GetID());
6521           }
6522           else {
6523             // each face has to be analyzed in order to check volume validity
6524             const SMDS_VtkVolume* aPolyedre =
6525               dynamic_cast<const SMDS_VtkVolume*>( elem );
6526             if (aPolyedre) {
6527               int nbFaces = aPolyedre->NbFaces();
6528
6529               vector<const SMDS_MeshNode *> poly_nodes;
6530               vector<int> quantities;
6531
6532               for (int iface = 1; iface <= nbFaces; iface++) {
6533                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6534                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
6535
6536                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
6537                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
6538                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
6539                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
6540                     faceNode = (*nnIt).second;
6541                   }
6542                   faceNodes[inode - 1] = faceNode;
6543                 }
6544
6545                 SimplifyFace(faceNodes, poly_nodes, quantities);
6546               }
6547
6548               if (quantities.size() > 3) {
6549                 // to be done: remove coincident faces
6550               }
6551
6552               if (quantities.size() > 3)
6553                 {
6554                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
6555                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6556                   const SMDS_MeshElement* newElem = 0;
6557                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
6558                   myLastCreatedElems.Append(newElem);
6559                   if ( aShapeId && newElem )
6560                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
6561                   rmElemIds.push_back(elem->GetID());
6562                 }
6563             }
6564             else {
6565               rmElemIds.push_back(elem->GetID());
6566             }
6567           }
6568         }
6569         else {
6570         }
6571
6572         continue;
6573       } // poly element
6574
6575       // Regular elements
6576       // TODO not all the possible cases are solved. Find something more generic?
6577       switch ( nbNodes ) {
6578       case 2: ///////////////////////////////////// EDGE
6579         isOk = false; break;
6580       case 3: ///////////////////////////////////// TRIANGLE
6581         isOk = false; break;
6582       case 4:
6583         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
6584           isOk = false;
6585         else { //////////////////////////////////// QUADRANGLE
6586           if ( nbUniqueNodes < 3 )
6587             isOk = false;
6588           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
6589             isOk = false; // opposite nodes stick
6590           //MESSAGE("isOk " << isOk);
6591         }
6592         break;
6593       case 6: ///////////////////////////////////// PENTAHEDRON
6594         if ( nbUniqueNodes == 4 ) {
6595           // ---------------------------------> tetrahedron
6596           if (nbRepl == 3 &&
6597               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
6598             // all top nodes stick: reverse a bottom
6599             uniqueNodes[ 0 ] = curNodes [ 1 ];
6600             uniqueNodes[ 1 ] = curNodes [ 0 ];
6601           }
6602           else if (nbRepl == 3 &&
6603                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
6604             // all bottom nodes stick: set a top before
6605             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
6606             uniqueNodes[ 0 ] = curNodes [ 3 ];
6607             uniqueNodes[ 1 ] = curNodes [ 4 ];
6608             uniqueNodes[ 2 ] = curNodes [ 5 ];
6609           }
6610           else if (nbRepl == 4 &&
6611                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
6612             // a lateral face turns into a line: reverse a bottom
6613             uniqueNodes[ 0 ] = curNodes [ 1 ];
6614             uniqueNodes[ 1 ] = curNodes [ 0 ];
6615           }
6616           else
6617             isOk = false;
6618         }
6619         else if ( nbUniqueNodes == 5 ) {
6620           // PENTAHEDRON --------------------> 2 tetrahedrons
6621           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6622             // a bottom node sticks with a linked top one
6623             // 1.
6624             SMDS_MeshElement* newElem =
6625               aMesh->AddVolume(curNodes[ 3 ],
6626                                curNodes[ 4 ],
6627                                curNodes[ 5 ],
6628                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6629             myLastCreatedElems.Append(newElem);
6630             if ( aShapeId )
6631               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6632             // 2. : reverse a bottom
6633             uniqueNodes[ 0 ] = curNodes [ 1 ];
6634             uniqueNodes[ 1 ] = curNodes [ 0 ];
6635             nbUniqueNodes = 4;
6636           }
6637           else
6638             isOk = false;
6639         }
6640         else
6641           isOk = false;
6642         break;
6643       case 8: {
6644         if(elem->IsQuadratic()) { // Quadratic quadrangle
6645           //   1    5    2
6646           //    +---+---+
6647           //    |       |
6648           //    |       |
6649           //   4+       +6
6650           //    |       |
6651           //    |       |
6652           //    +---+---+
6653           //   0    7    3
6654           isOk = false;
6655           if(nbRepl==2) {
6656             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
6657           }
6658           if(nbRepl==3) {
6659             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
6660             nbUniqueNodes = 6;
6661             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6662               uniqueNodes[0] = curNodes[0];
6663               uniqueNodes[1] = curNodes[2];
6664               uniqueNodes[2] = curNodes[3];
6665               uniqueNodes[3] = curNodes[5];
6666               uniqueNodes[4] = curNodes[6];
6667               uniqueNodes[5] = curNodes[7];
6668               isOk = true;
6669             }
6670             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6671               uniqueNodes[0] = curNodes[0];
6672               uniqueNodes[1] = curNodes[1];
6673               uniqueNodes[2] = curNodes[2];
6674               uniqueNodes[3] = curNodes[4];
6675               uniqueNodes[4] = curNodes[5];
6676               uniqueNodes[5] = curNodes[6];
6677               isOk = true;
6678             }
6679             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6680               uniqueNodes[0] = curNodes[1];
6681               uniqueNodes[1] = curNodes[2];
6682               uniqueNodes[2] = curNodes[3];
6683               uniqueNodes[3] = curNodes[5];
6684               uniqueNodes[4] = curNodes[6];
6685               uniqueNodes[5] = curNodes[0];
6686               isOk = true;
6687             }
6688             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
6689               uniqueNodes[0] = curNodes[0];
6690               uniqueNodes[1] = curNodes[1];
6691               uniqueNodes[2] = curNodes[3];
6692               uniqueNodes[3] = curNodes[4];
6693               uniqueNodes[4] = curNodes[6];
6694               uniqueNodes[5] = curNodes[7];
6695               isOk = true;
6696             }
6697             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
6698               uniqueNodes[0] = curNodes[0];
6699               uniqueNodes[1] = curNodes[2];
6700               uniqueNodes[2] = curNodes[3];
6701               uniqueNodes[3] = curNodes[1];
6702               uniqueNodes[4] = curNodes[6];
6703               uniqueNodes[5] = curNodes[7];
6704               isOk = true;
6705             }
6706             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
6707               uniqueNodes[0] = curNodes[0];
6708               uniqueNodes[1] = curNodes[1];
6709               uniqueNodes[2] = curNodes[2];
6710               uniqueNodes[3] = curNodes[4];
6711               uniqueNodes[4] = curNodes[5];
6712               uniqueNodes[5] = curNodes[7];
6713               isOk = true;
6714             }
6715             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
6716               uniqueNodes[0] = curNodes[0];
6717               uniqueNodes[1] = curNodes[1];
6718               uniqueNodes[2] = curNodes[3];
6719               uniqueNodes[3] = curNodes[4];
6720               uniqueNodes[4] = curNodes[2];
6721               uniqueNodes[5] = curNodes[7];
6722               isOk = true;
6723             }
6724             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
6725               uniqueNodes[0] = curNodes[0];
6726               uniqueNodes[1] = curNodes[1];
6727               uniqueNodes[2] = curNodes[2];
6728               uniqueNodes[3] = curNodes[4];
6729               uniqueNodes[4] = curNodes[5];
6730               uniqueNodes[5] = curNodes[3];
6731               isOk = true;
6732             }
6733           }
6734           if(nbRepl==4) {
6735             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
6736           }
6737           if(nbRepl==5) {
6738             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
6739           }
6740           break;
6741         }
6742         //////////////////////////////////// HEXAHEDRON
6743         isOk = false;
6744         SMDS_VolumeTool hexa (elem);
6745         hexa.SetExternalNormal();
6746         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
6747           //////////////////////// HEX ---> 1 tetrahedron
6748           for ( int iFace = 0; iFace < 6; iFace++ ) {
6749             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6750             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6751                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6752                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6753               // one face turns into a point ...
6754               int iOppFace = hexa.GetOppFaceIndex( iFace );
6755               ind = hexa.GetFaceNodesIndices( iOppFace );
6756               int nbStick = 0;
6757               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
6758                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6759                   nbStick++;
6760               }
6761               if ( nbStick == 1 ) {
6762                 // ... and the opposite one - into a triangle.
6763                 // set a top node
6764                 ind = hexa.GetFaceNodesIndices( iFace );
6765                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
6766                 isOk = true;
6767               }
6768               break;
6769             }
6770           }
6771         }
6772         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
6773           //////////////////////// HEX ---> 1 prism
6774           int nbTria = 0, iTria[3];
6775           const int *ind; // indices of face nodes
6776           // look for triangular faces
6777           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
6778             ind = hexa.GetFaceNodesIndices( iFace );
6779             TIDSortedNodeSet faceNodes;
6780             for ( iCur = 0; iCur < 4; iCur++ )
6781               faceNodes.insert( curNodes[ind[iCur]] );
6782             if ( faceNodes.size() == 3 )
6783               iTria[ nbTria++ ] = iFace;
6784           }
6785           // check if triangles are opposite
6786           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
6787           {
6788             isOk = true;
6789             // set nodes of the bottom triangle
6790             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
6791             vector<int> indB;
6792             for ( iCur = 0; iCur < 4; iCur++ )
6793               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
6794                 indB.push_back( ind[iCur] );
6795             if ( !hexa.IsForward() )
6796               std::swap( indB[0], indB[2] );
6797             for ( iCur = 0; iCur < 3; iCur++ )
6798               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
6799             // set nodes of the top triangle
6800             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
6801             for ( iCur = 0; iCur < 3; ++iCur )
6802               for ( int j = 0; j < 4; ++j )
6803                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
6804                 {
6805                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
6806                   break;
6807                 }
6808           }
6809           break;
6810         }
6811         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
6812           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
6813           for ( int iFace = 0; iFace < 6; iFace++ ) {
6814             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6815             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6816                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6817                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6818               // one face turns into a point ...
6819               int iOppFace = hexa.GetOppFaceIndex( iFace );
6820               ind = hexa.GetFaceNodesIndices( iOppFace );
6821               int nbStick = 0;
6822               iUnique = 2;  // reverse a tetrahedron 1 bottom
6823               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
6824                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6825                   nbStick++;
6826                 else if ( iUnique >= 0 )
6827                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6828               }
6829               if ( nbStick == 0 ) {
6830                 // ... and the opposite one is a quadrangle
6831                 // set a top node
6832                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
6833                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
6834                 nbUniqueNodes = 4;
6835                 // tetrahedron 2
6836                 SMDS_MeshElement* newElem =
6837                   aMesh->AddVolume(curNodes[ind[ 0 ]],
6838                                    curNodes[ind[ 3 ]],
6839                                    curNodes[ind[ 2 ]],
6840                                    curNodes[indTop[ 0 ]]);
6841                 myLastCreatedElems.Append(newElem);
6842                 if ( aShapeId )
6843                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
6844                 isOk = true;
6845               }
6846               break;
6847             }
6848           }
6849         }
6850         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
6851           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
6852           // find indices of quad and tri faces
6853           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
6854           for ( iFace = 0; iFace < 6; iFace++ ) {
6855             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6856             nodeSet.clear();
6857             for ( iCur = 0; iCur < 4; iCur++ )
6858               nodeSet.insert( curNodes[ind[ iCur ]] );
6859             nbUniqueNodes = nodeSet.size();
6860             if ( nbUniqueNodes == 3 )
6861               iTriFace[ nbTri++ ] = iFace;
6862             else if ( nbUniqueNodes == 4 )
6863               iQuadFace[ nbQuad++ ] = iFace;
6864           }
6865           if (nbQuad == 2 && nbTri == 4 &&
6866               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
6867             // 2 opposite quadrangles stuck with a diagonal;
6868             // sample groups of merged indices: (0-4)(2-6)
6869             // --------------------------------------------> 2 tetrahedrons
6870             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
6871             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
6872             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
6873             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
6874                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
6875               // stuck with 0-2 diagonal
6876               i0  = ind1[ 3 ];
6877               i1d = ind1[ 0 ];
6878               i2  = ind1[ 1 ];
6879               i3d = ind1[ 2 ];
6880               i0t = ind2[ 1 ];
6881               i2t = ind2[ 3 ];
6882             }
6883             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
6884                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
6885               // stuck with 1-3 diagonal
6886               i0  = ind1[ 0 ];
6887               i1d = ind1[ 1 ];
6888               i2  = ind1[ 2 ];
6889               i3d = ind1[ 3 ];
6890               i0t = ind2[ 0 ];
6891               i2t = ind2[ 1 ];
6892             }
6893             else {
6894               ASSERT(0);
6895             }
6896             // tetrahedron 1
6897             uniqueNodes[ 0 ] = curNodes [ i0 ];
6898             uniqueNodes[ 1 ] = curNodes [ i1d ];
6899             uniqueNodes[ 2 ] = curNodes [ i3d ];
6900             uniqueNodes[ 3 ] = curNodes [ i0t ];
6901             nbUniqueNodes = 4;
6902             // tetrahedron 2
6903             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
6904                                                          curNodes[ i2 ],
6905                                                          curNodes[ i3d ],
6906                                                          curNodes[ i2t ]);
6907             myLastCreatedElems.Append(newElem);
6908             if ( aShapeId )
6909               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6910             isOk = true;
6911           }
6912           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
6913                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
6914             // --------------------------------------------> prism
6915             // find 2 opposite triangles
6916             nbUniqueNodes = 6;
6917             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
6918               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
6919                 // find indices of kept and replaced nodes
6920                 // and fill unique nodes of 2 opposite triangles
6921                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
6922                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
6923                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
6924                 // fill unique nodes
6925                 iUnique = 0;
6926                 isOk = true;
6927                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
6928                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
6929                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
6930                   if ( n == nInit ) {
6931                     // iCur of a linked node of the opposite face (make normals co-directed):
6932                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
6933                     // check that correspondent corners of triangles are linked
6934                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
6935                       isOk = false;
6936                     else {
6937                       uniqueNodes[ iUnique ] = n;
6938                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
6939                       iUnique++;
6940                     }
6941                   }
6942                 }
6943                 break;
6944               }
6945             }
6946           }
6947         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
6948         else
6949         {
6950           MESSAGE("MergeNodes() removes hexahedron "<< elem);
6951         }
6952         break;
6953       } // HEXAHEDRON
6954
6955       default:
6956         isOk = false;
6957       } // switch ( nbNodes )
6958
6959     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
6960
6961     if ( isOk ) { // the elem remains valid after sticking nodes
6962       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
6963       {
6964         // Change nodes of polyedre
6965         const SMDS_VtkVolume* aPolyedre =
6966           dynamic_cast<const SMDS_VtkVolume*>( elem );
6967         if (aPolyedre) {
6968           int nbFaces = aPolyedre->NbFaces();
6969
6970           vector<const SMDS_MeshNode *> poly_nodes;
6971           vector<int> quantities (nbFaces);
6972
6973           for (int iface = 1; iface <= nbFaces; iface++) {
6974             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6975             quantities[iface - 1] = nbFaceNodes;
6976
6977             for (inode = 1; inode <= nbFaceNodes; inode++) {
6978               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
6979
6980               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
6981               if (nnIt != nodeNodeMap.end()) { // curNode sticks
6982                 curNode = (*nnIt).second;
6983               }
6984               poly_nodes.push_back(curNode);
6985             }
6986           }
6987           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
6988         }
6989       }
6990       else // replace non-polyhedron elements
6991       {
6992         const SMDSAbs_ElementType etyp = elem->GetType();
6993         const int elemId               = elem->GetID();
6994         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
6995         uniqueNodes.resize(nbUniqueNodes);
6996
6997         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
6998
6999         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7000         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
7001         if ( sm && newElem )
7002           sm->AddElement( newElem );
7003         if ( elem != newElem )
7004           ReplaceElemInGroups( elem, newElem, aMesh );
7005       }
7006     }
7007     else {
7008       // Remove invalid regular element or invalid polygon
7009       rmElemIds.push_back( elem->GetID() );
7010     }
7011
7012   } // loop on elements
7013
7014   // Remove bad elements, then equal nodes (order important)
7015
7016   Remove( rmElemIds, false );
7017   Remove( rmNodeIds, true );
7018
7019 }
7020
7021
7022 // ========================================================
7023 // class   : SortableElement
7024 // purpose : allow sorting elements basing on their nodes
7025 // ========================================================
7026 class SortableElement : public set <const SMDS_MeshElement*>
7027 {
7028 public:
7029
7030   SortableElement( const SMDS_MeshElement* theElem )
7031   {
7032     myElem = theElem;
7033     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7034     while ( nodeIt->more() )
7035       this->insert( nodeIt->next() );
7036   }
7037
7038   const SMDS_MeshElement* Get() const
7039   { return myElem; }
7040
7041   void Set(const SMDS_MeshElement* e) const
7042   { myElem = e; }
7043
7044
7045 private:
7046   mutable const SMDS_MeshElement* myElem;
7047 };
7048
7049 //=======================================================================
7050 //function : FindEqualElements
7051 //purpose  : Return list of group of elements built on the same nodes.
7052 //           Search among theElements or in the whole mesh if theElements is empty
7053 //=======================================================================
7054
7055 void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet &        theElements,
7056                                          TListOfListOfElementsID & theGroupsOfElementsID)
7057 {
7058   myLastCreatedElems.Clear();
7059   myLastCreatedNodes.Clear();
7060
7061   typedef map< SortableElement, int > TMapOfNodeSet;
7062   typedef list<int> TGroupOfElems;
7063
7064   if ( theElements.empty() )
7065   { // get all elements in the mesh
7066     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7067     while ( eIt->more() )
7068       theElements.insert( theElements.end(), eIt->next());
7069   }
7070
7071   vector< TGroupOfElems > arrayOfGroups;
7072   TGroupOfElems groupOfElems;
7073   TMapOfNodeSet mapOfNodeSet;
7074
7075   TIDSortedElemSet::iterator elemIt = theElements.begin();
7076   for ( int i = 0, j=0; elemIt != theElements.end(); ++elemIt, ++j ) {
7077     const SMDS_MeshElement* curElem = *elemIt;
7078     SortableElement SE(curElem);
7079     int ind = -1;
7080     // check uniqueness
7081     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7082     if( !(pp.second) ) {
7083       TMapOfNodeSet::iterator& itSE = pp.first;
7084       ind = (*itSE).second;
7085       arrayOfGroups[ind].push_back(curElem->GetID());
7086     }
7087     else {
7088       groupOfElems.clear();
7089       groupOfElems.push_back(curElem->GetID());
7090       arrayOfGroups.push_back(groupOfElems);
7091       i++;
7092     }
7093   }
7094
7095   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7096   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7097     groupOfElems = *groupIt;
7098     if ( groupOfElems.size() > 1 ) {
7099       groupOfElems.sort();
7100       theGroupsOfElementsID.push_back(groupOfElems);
7101     }
7102   }
7103 }
7104
7105 //=======================================================================
7106 //function : MergeElements
7107 //purpose  : In each given group, substitute all elements by the first one.
7108 //=======================================================================
7109
7110 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7111 {
7112   myLastCreatedElems.Clear();
7113   myLastCreatedNodes.Clear();
7114
7115   typedef list<int> TListOfIDs;
7116   TListOfIDs rmElemIds; // IDs of elems to remove
7117
7118   SMESHDS_Mesh* aMesh = GetMeshDS();
7119
7120   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7121   while ( groupsIt != theGroupsOfElementsID.end() ) {
7122     TListOfIDs& aGroupOfElemID = *groupsIt;
7123     aGroupOfElemID.sort();
7124     int elemIDToKeep = aGroupOfElemID.front();
7125     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7126     aGroupOfElemID.pop_front();
7127     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7128     while ( idIt != aGroupOfElemID.end() ) {
7129       int elemIDToRemove = *idIt;
7130       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7131       // add the kept element in groups of removed one (PAL15188)
7132       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7133       rmElemIds.push_back( elemIDToRemove );
7134       ++idIt;
7135     }
7136     ++groupsIt;
7137   }
7138
7139   Remove( rmElemIds, false );
7140 }
7141
7142 //=======================================================================
7143 //function : MergeEqualElements
7144 //purpose  : Remove all but one of elements built on the same nodes.
7145 //=======================================================================
7146
7147 void SMESH_MeshEditor::MergeEqualElements()
7148 {
7149   TIDSortedElemSet aMeshElements; /* empty input ==
7150                                      to merge equal elements in the whole mesh */
7151   TListOfListOfElementsID aGroupsOfElementsID;
7152   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7153   MergeElements(aGroupsOfElementsID);
7154 }
7155
7156 //=======================================================================
7157 //function : findAdjacentFace
7158 //purpose  :
7159 //=======================================================================
7160
7161 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7162                                                 const SMDS_MeshNode* n2,
7163                                                 const SMDS_MeshElement* elem)
7164 {
7165   TIDSortedElemSet elemSet, avoidSet;
7166   if ( elem )
7167     avoidSet.insert ( elem );
7168   return SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet );
7169 }
7170
7171 //=======================================================================
7172 //function : FindFreeBorder
7173 //purpose  :
7174 //=======================================================================
7175
7176 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7177
7178 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7179                                        const SMDS_MeshNode*             theSecondNode,
7180                                        const SMDS_MeshNode*             theLastNode,
7181                                        list< const SMDS_MeshNode* > &   theNodes,
7182                                        list< const SMDS_MeshElement* >& theFaces)
7183 {
7184   if ( !theFirstNode || !theSecondNode )
7185     return false;
7186   // find border face between theFirstNode and theSecondNode
7187   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7188   if ( !curElem )
7189     return false;
7190
7191   theFaces.push_back( curElem );
7192   theNodes.push_back( theFirstNode );
7193   theNodes.push_back( theSecondNode );
7194
7195   //vector<const SMDS_MeshNode*> nodes;
7196   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7197   TIDSortedElemSet foundElems;
7198   bool needTheLast = ( theLastNode != 0 );
7199
7200   while ( nStart != theLastNode ) {
7201     if ( nStart == theFirstNode )
7202       return !needTheLast;
7203
7204     // find all free border faces sharing form nStart
7205
7206     list< const SMDS_MeshElement* > curElemList;
7207     list< const SMDS_MeshNode* > nStartList;
7208     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7209     while ( invElemIt->more() ) {
7210       const SMDS_MeshElement* e = invElemIt->next();
7211       if ( e == curElem || foundElems.insert( e ).second ) {
7212         // get nodes
7213         int iNode = 0, nbNodes = e->NbNodes();
7214         //const SMDS_MeshNode* nodes[nbNodes+1];
7215         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7216
7217         if(e->IsQuadratic()) {
7218           const SMDS_VtkFace* F =
7219             dynamic_cast<const SMDS_VtkFace*>(e);
7220           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7221           // use special nodes iterator
7222           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7223           while( anIter->more() ) {
7224             nodes[ iNode++ ] = cast2Node(anIter->next());
7225           }
7226         }
7227         else {
7228           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7229           while ( nIt->more() )
7230             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7231         }
7232         nodes[ iNode ] = nodes[ 0 ];
7233         // check 2 links
7234         for ( iNode = 0; iNode < nbNodes; iNode++ )
7235           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7236                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7237               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7238           {
7239             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7240             curElemList.push_back( e );
7241           }
7242       }
7243     }
7244     // analyse the found
7245
7246     int nbNewBorders = curElemList.size();
7247     if ( nbNewBorders == 0 ) {
7248       // no free border furthermore
7249       return !needTheLast;
7250     }
7251     else if ( nbNewBorders == 1 ) {
7252       // one more element found
7253       nIgnore = nStart;
7254       nStart = nStartList.front();
7255       curElem = curElemList.front();
7256       theFaces.push_back( curElem );
7257       theNodes.push_back( nStart );
7258     }
7259     else {
7260       // several continuations found
7261       list< const SMDS_MeshElement* >::iterator curElemIt;
7262       list< const SMDS_MeshNode* >::iterator nStartIt;
7263       // check if one of them reached the last node
7264       if ( needTheLast ) {
7265         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7266              curElemIt!= curElemList.end();
7267              curElemIt++, nStartIt++ )
7268           if ( *nStartIt == theLastNode ) {
7269             theFaces.push_back( *curElemIt );
7270             theNodes.push_back( *nStartIt );
7271             return true;
7272           }
7273       }
7274       // find the best free border by the continuations
7275       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7276       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7277       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7278            curElemIt!= curElemList.end();
7279            curElemIt++, nStartIt++ )
7280       {
7281         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7282         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7283         // find one more free border
7284         if ( ! SMESH_MeshEditor::FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7285           cNL->clear();
7286           cFL->clear();
7287         }
7288         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7289           // choice: clear a worse one
7290           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7291           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7292           contNodes[ iWorse ].clear();
7293           contFaces[ iWorse ].clear();
7294         }
7295       }
7296       if ( contNodes[0].empty() && contNodes[1].empty() )
7297         return false;
7298
7299       // append the best free border
7300       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7301       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7302       theNodes.pop_back(); // remove nIgnore
7303       theNodes.pop_back(); // remove nStart
7304       theFaces.pop_back(); // remove curElem
7305       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7306       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7307       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7308       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7309       return true;
7310
7311     } // several continuations found
7312   } // while ( nStart != theLastNode )
7313
7314   return true;
7315 }
7316
7317 //=======================================================================
7318 //function : CheckFreeBorderNodes
7319 //purpose  : Return true if the tree nodes are on a free border
7320 //=======================================================================
7321
7322 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7323                                             const SMDS_MeshNode* theNode2,
7324                                             const SMDS_MeshNode* theNode3)
7325 {
7326   list< const SMDS_MeshNode* > nodes;
7327   list< const SMDS_MeshElement* > faces;
7328   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7329 }
7330
7331 //=======================================================================
7332 //function : SewFreeBorder
7333 //purpose  :
7334 //=======================================================================
7335
7336 SMESH_MeshEditor::Sew_Error
7337 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7338                                  const SMDS_MeshNode* theBordSecondNode,
7339                                  const SMDS_MeshNode* theBordLastNode,
7340                                  const SMDS_MeshNode* theSideFirstNode,
7341                                  const SMDS_MeshNode* theSideSecondNode,
7342                                  const SMDS_MeshNode* theSideThirdNode,
7343                                  const bool           theSideIsFreeBorder,
7344                                  const bool           toCreatePolygons,
7345                                  const bool           toCreatePolyedrs)
7346 {
7347   myLastCreatedElems.Clear();
7348   myLastCreatedNodes.Clear();
7349
7350   MESSAGE("::SewFreeBorder()");
7351   Sew_Error aResult = SEW_OK;
7352
7353   // ====================================
7354   //    find side nodes and elements
7355   // ====================================
7356
7357   list< const SMDS_MeshNode* > nSide[ 2 ];
7358   list< const SMDS_MeshElement* > eSide[ 2 ];
7359   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7360   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7361
7362   // Free border 1
7363   // --------------
7364   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7365                       nSide[0], eSide[0])) {
7366     MESSAGE(" Free Border 1 not found " );
7367     aResult = SEW_BORDER1_NOT_FOUND;
7368   }
7369   if (theSideIsFreeBorder) {
7370     // Free border 2
7371     // --------------
7372     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7373                         nSide[1], eSide[1])) {
7374       MESSAGE(" Free Border 2 not found " );
7375       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7376     }
7377   }
7378   if ( aResult != SEW_OK )
7379     return aResult;
7380
7381   if (!theSideIsFreeBorder) {
7382     // Side 2
7383     // --------------
7384
7385     // -------------------------------------------------------------------------
7386     // Algo:
7387     // 1. If nodes to merge are not coincident, move nodes of the free border
7388     //    from the coord sys defined by the direction from the first to last
7389     //    nodes of the border to the correspondent sys of the side 2
7390     // 2. On the side 2, find the links most co-directed with the correspondent
7391     //    links of the free border
7392     // -------------------------------------------------------------------------
7393
7394     // 1. Since sewing may break if there are volumes to split on the side 2,
7395     //    we wont move nodes but just compute new coordinates for them
7396     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7397     TNodeXYZMap nBordXYZ;
7398     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7399     list< const SMDS_MeshNode* >::iterator nBordIt;
7400
7401     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7402     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7403     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7404     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7405     double tol2 = 1.e-8;
7406     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7407     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7408       // Need node movement.
7409
7410       // find X and Z axes to create trsf
7411       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7412       gp_Vec X = Zs ^ Zb;
7413       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7414         // Zb || Zs
7415         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7416
7417       // coord systems
7418       gp_Ax3 toBordAx( Pb1, Zb, X );
7419       gp_Ax3 fromSideAx( Ps1, Zs, X );
7420       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7421       // set trsf
7422       gp_Trsf toBordSys, fromSide2Sys;
7423       toBordSys.SetTransformation( toBordAx );
7424       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7425       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7426
7427       // move
7428       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7429         const SMDS_MeshNode* n = *nBordIt;
7430         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7431         toBordSys.Transforms( xyz );
7432         fromSide2Sys.Transforms( xyz );
7433         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7434       }
7435     }
7436     else {
7437       // just insert nodes XYZ in the nBordXYZ map
7438       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7439         const SMDS_MeshNode* n = *nBordIt;
7440         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7441       }
7442     }
7443
7444     // 2. On the side 2, find the links most co-directed with the correspondent
7445     //    links of the free border
7446
7447     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7448     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7449     sideNodes.push_back( theSideFirstNode );
7450
7451     bool hasVolumes = false;
7452     LinkID_Gen aLinkID_Gen( GetMeshDS() );
7453     set<long> foundSideLinkIDs, checkedLinkIDs;
7454     SMDS_VolumeTool volume;
7455     //const SMDS_MeshNode* faceNodes[ 4 ];
7456
7457     const SMDS_MeshNode*    sideNode;
7458     const SMDS_MeshElement* sideElem;
7459     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7460     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7461     nBordIt = bordNodes.begin();
7462     nBordIt++;
7463     // border node position and border link direction to compare with
7464     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7465     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7466     // choose next side node by link direction or by closeness to
7467     // the current border node:
7468     bool searchByDir = ( *nBordIt != theBordLastNode );
7469     do {
7470       // find the next node on the Side 2
7471       sideNode = 0;
7472       double maxDot = -DBL_MAX, minDist = DBL_MAX;
7473       long linkID;
7474       checkedLinkIDs.clear();
7475       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7476
7477       // loop on inverse elements of current node (prevSideNode) on the Side 2
7478       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7479       while ( invElemIt->more() )
7480       {
7481         const SMDS_MeshElement* elem = invElemIt->next();
7482         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7483         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7484         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7485         bool isVolume = volume.Set( elem );
7486         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7487         if ( isVolume ) // --volume
7488           hasVolumes = true;
7489         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7490           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7491           if(elem->IsQuadratic()) {
7492             const SMDS_VtkFace* F =
7493               dynamic_cast<const SMDS_VtkFace*>(elem);
7494             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7495             // use special nodes iterator
7496             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7497             while( anIter->more() ) {
7498               nodes[ iNode ] = cast2Node(anIter->next());
7499               if ( nodes[ iNode++ ] == prevSideNode )
7500                 iPrevNode = iNode - 1;
7501             }
7502           }
7503           else {
7504             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7505             while ( nIt->more() ) {
7506               nodes[ iNode ] = cast2Node( nIt->next() );
7507               if ( nodes[ iNode++ ] == prevSideNode )
7508                 iPrevNode = iNode - 1;
7509             }
7510           }
7511           // there are 2 links to check
7512           nbNodes = 2;
7513         }
7514         else // --edge
7515           continue;
7516         // loop on links, to be precise, on the second node of links
7517         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7518           const SMDS_MeshNode* n = nodes[ iNode ];
7519           if ( isVolume ) {
7520             if ( !volume.IsLinked( n, prevSideNode ))
7521               continue;
7522           }
7523           else {
7524             if ( iNode ) // a node before prevSideNode
7525               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7526             else         // a node after prevSideNode
7527               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7528           }
7529           // check if this link was already used
7530           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7531           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7532           if (!isJustChecked &&
7533               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7534           {
7535             // test a link geometrically
7536             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
7537             bool linkIsBetter = false;
7538             double dot = 0.0, dist = 0.0;
7539             if ( searchByDir ) { // choose most co-directed link
7540               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
7541               linkIsBetter = ( dot > maxDot );
7542             }
7543             else { // choose link with the node closest to bordPos
7544               dist = ( nextXYZ - bordPos ).SquareModulus();
7545               linkIsBetter = ( dist < minDist );
7546             }
7547             if ( linkIsBetter ) {
7548               maxDot = dot;
7549               minDist = dist;
7550               linkID = iLink;
7551               sideNode = n;
7552               sideElem = elem;
7553             }
7554           }
7555         }
7556       } // loop on inverse elements of prevSideNode
7557
7558       if ( !sideNode ) {
7559         MESSAGE(" Cant find path by links of the Side 2 ");
7560         return SEW_BAD_SIDE_NODES;
7561       }
7562       sideNodes.push_back( sideNode );
7563       sideElems.push_back( sideElem );
7564       foundSideLinkIDs.insert ( linkID );
7565       prevSideNode = sideNode;
7566
7567       if ( *nBordIt == theBordLastNode )
7568         searchByDir = false;
7569       else {
7570         // find the next border link to compare with
7571         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
7572         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7573         // move to next border node if sideNode is before forward border node (bordPos)
7574         while ( *nBordIt != theBordLastNode && !searchByDir ) {
7575           prevBordNode = *nBordIt;
7576           nBordIt++;
7577           bordPos = nBordXYZ[ *nBordIt ];
7578           bordDir = bordPos - nBordXYZ[ prevBordNode ];
7579           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7580         }
7581       }
7582     }
7583     while ( sideNode != theSideSecondNode );
7584
7585     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
7586       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
7587       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
7588     }
7589   } // end nodes search on the side 2
7590
7591   // ============================
7592   // sew the border to the side 2
7593   // ============================
7594
7595   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
7596   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
7597
7598   TListOfListOfNodes nodeGroupsToMerge;
7599   if ( nbNodes[0] == nbNodes[1] ||
7600        ( theSideIsFreeBorder && !theSideThirdNode)) {
7601
7602     // all nodes are to be merged
7603
7604     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
7605          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
7606          nIt[0]++, nIt[1]++ )
7607     {
7608       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7609       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
7610       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
7611     }
7612   }
7613   else {
7614
7615     // insert new nodes into the border and the side to get equal nb of segments
7616
7617     // get normalized parameters of nodes on the borders
7618     //double param[ 2 ][ maxNbNodes ];
7619     double* param[ 2 ];
7620     param[0] = new double [ maxNbNodes ];
7621     param[1] = new double [ maxNbNodes ];
7622     int iNode, iBord;
7623     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7624       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7625       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
7626       const SMDS_MeshNode* nPrev = *nIt;
7627       double bordLength = 0;
7628       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7629         const SMDS_MeshNode* nCur = *nIt;
7630         gp_XYZ segment (nCur->X() - nPrev->X(),
7631                         nCur->Y() - nPrev->Y(),
7632                         nCur->Z() - nPrev->Z());
7633         double segmentLen = segment.Modulus();
7634         bordLength += segmentLen;
7635         param[ iBord ][ iNode ] = bordLength;
7636         nPrev = nCur;
7637       }
7638       // normalize within [0,1]
7639       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7640         param[ iBord ][ iNode ] /= bordLength;
7641       }
7642     }
7643
7644     // loop on border segments
7645     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7646     int i[ 2 ] = { 0, 0 };
7647     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7648     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7649
7650     TElemOfNodeListMap insertMap;
7651     TElemOfNodeListMap::iterator insertMapIt;
7652     // insertMap is
7653     // key:   elem to insert nodes into
7654     // value: 2 nodes to insert between + nodes to be inserted
7655     do {
7656       bool next[ 2 ] = { false, false };
7657
7658       // find min adjacent segment length after sewing
7659       double nextParam = 10., prevParam = 0;
7660       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7661         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7662           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7663         if ( i[ iBord ] > 0 )
7664           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7665       }
7666       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7667       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7668       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7669
7670       // choose to insert or to merge nodes
7671       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7672       if ( Abs( du ) <= minSegLen * 0.2 ) {
7673         // merge
7674         // ------
7675         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7676         const SMDS_MeshNode* n0 = *nIt[0];
7677         const SMDS_MeshNode* n1 = *nIt[1];
7678         nodeGroupsToMerge.back().push_back( n1 );
7679         nodeGroupsToMerge.back().push_back( n0 );
7680         // position of node of the border changes due to merge
7681         param[ 0 ][ i[0] ] += du;
7682         // move n1 for the sake of elem shape evaluation during insertion.
7683         // n1 will be removed by MergeNodes() anyway
7684         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
7685         next[0] = next[1] = true;
7686       }
7687       else {
7688         // insert
7689         // ------
7690         int intoBord = ( du < 0 ) ? 0 : 1;
7691         const SMDS_MeshElement* elem = *eIt[ intoBord ];
7692         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
7693         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
7694         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
7695         if ( intoBord == 1 ) {
7696           // move node of the border to be on a link of elem of the side
7697           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
7698           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
7699           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
7700           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
7701           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
7702         }
7703         insertMapIt = insertMap.find( elem );
7704         bool notFound = ( insertMapIt == insertMap.end() );
7705         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
7706         if ( otherLink ) {
7707           // insert into another link of the same element:
7708           // 1. perform insertion into the other link of the elem
7709           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7710           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
7711           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
7712           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
7713           // 2. perform insertion into the link of adjacent faces
7714           while (true) {
7715             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
7716             if ( adjElem )
7717               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
7718             else
7719               break;
7720           }
7721           if (toCreatePolyedrs) {
7722             // perform insertion into the links of adjacent volumes
7723             UpdateVolumes(n12, n22, nodeList);
7724           }
7725           // 3. find an element appeared on n1 and n2 after the insertion
7726           insertMap.erase( elem );
7727           elem = findAdjacentFace( n1, n2, 0 );
7728         }
7729         if ( notFound || otherLink ) {
7730           // add element and nodes of the side into the insertMap
7731           insertMapIt = insertMap.insert
7732             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
7733           (*insertMapIt).second.push_back( n1 );
7734           (*insertMapIt).second.push_back( n2 );
7735         }
7736         // add node to be inserted into elem
7737         (*insertMapIt).second.push_back( nIns );
7738         next[ 1 - intoBord ] = true;
7739       }
7740
7741       // go to the next segment
7742       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7743         if ( next[ iBord ] ) {
7744           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
7745             eIt[ iBord ]++;
7746           nPrev[ iBord ] = *nIt[ iBord ];
7747           nIt[ iBord ]++; i[ iBord ]++;
7748         }
7749       }
7750     }
7751     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
7752
7753     // perform insertion of nodes into elements
7754
7755     for (insertMapIt = insertMap.begin();
7756          insertMapIt != insertMap.end();
7757          insertMapIt++ )
7758     {
7759       const SMDS_MeshElement* elem = (*insertMapIt).first;
7760       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7761       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
7762       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
7763
7764       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
7765
7766       if ( !theSideIsFreeBorder ) {
7767         // look for and insert nodes into the faces adjacent to elem
7768         while (true) {
7769           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
7770           if ( adjElem )
7771             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
7772           else
7773             break;
7774         }
7775       }
7776       if (toCreatePolyedrs) {
7777         // perform insertion into the links of adjacent volumes
7778         UpdateVolumes(n1, n2, nodeList);
7779       }
7780     }
7781
7782     delete param[0];
7783     delete param[1];
7784   } // end: insert new nodes
7785
7786   MergeNodes ( nodeGroupsToMerge );
7787
7788   return aResult;
7789 }
7790
7791 //=======================================================================
7792 //function : InsertNodesIntoLink
7793 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
7794 //           and theBetweenNode2 and split theElement
7795 //=======================================================================
7796
7797 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
7798                                            const SMDS_MeshNode*        theBetweenNode1,
7799                                            const SMDS_MeshNode*        theBetweenNode2,
7800                                            list<const SMDS_MeshNode*>& theNodesToInsert,
7801                                            const bool                  toCreatePoly)
7802 {
7803   if ( theFace->GetType() != SMDSAbs_Face ) return;
7804
7805   // find indices of 2 link nodes and of the rest nodes
7806   int iNode = 0, il1, il2, i3, i4;
7807   il1 = il2 = i3 = i4 = -1;
7808   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
7809   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
7810
7811   if(theFace->IsQuadratic()) {
7812     const SMDS_VtkFace* F =
7813       dynamic_cast<const SMDS_VtkFace*>(theFace);
7814     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7815     // use special nodes iterator
7816     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7817     while( anIter->more() ) {
7818       const SMDS_MeshNode* n = cast2Node(anIter->next());
7819       if ( n == theBetweenNode1 )
7820         il1 = iNode;
7821       else if ( n == theBetweenNode2 )
7822         il2 = iNode;
7823       else if ( i3 < 0 )
7824         i3 = iNode;
7825       else
7826         i4 = iNode;
7827       nodes[ iNode++ ] = n;
7828     }
7829   }
7830   else {
7831     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7832     while ( nodeIt->more() ) {
7833       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7834       if ( n == theBetweenNode1 )
7835         il1 = iNode;
7836       else if ( n == theBetweenNode2 )
7837         il2 = iNode;
7838       else if ( i3 < 0 )
7839         i3 = iNode;
7840       else
7841         i4 = iNode;
7842       nodes[ iNode++ ] = n;
7843     }
7844   }
7845   if ( il1 < 0 || il2 < 0 || i3 < 0 )
7846     return ;
7847
7848   // arrange link nodes to go one after another regarding the face orientation
7849   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
7850   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
7851   if ( reverse ) {
7852     iNode = il1;
7853     il1 = il2;
7854     il2 = iNode;
7855     aNodesToInsert.reverse();
7856   }
7857   // check that not link nodes of a quadrangles are in good order
7858   int nbFaceNodes = theFace->NbNodes();
7859   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
7860     iNode = i3;
7861     i3 = i4;
7862     i4 = iNode;
7863   }
7864
7865   if (toCreatePoly || theFace->IsPoly()) {
7866
7867     iNode = 0;
7868     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
7869
7870     // add nodes of face up to first node of link
7871     bool isFLN = false;
7872
7873     if(theFace->IsQuadratic()) {
7874       const SMDS_VtkFace* F =
7875         dynamic_cast<const SMDS_VtkFace*>(theFace);
7876       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7877       // use special nodes iterator
7878       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7879       while( anIter->more()  && !isFLN ) {
7880         const SMDS_MeshNode* n = cast2Node(anIter->next());
7881         poly_nodes[iNode++] = n;
7882         if (n == nodes[il1]) {
7883           isFLN = true;
7884         }
7885       }
7886       // add nodes to insert
7887       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7888       for (; nIt != aNodesToInsert.end(); nIt++) {
7889         poly_nodes[iNode++] = *nIt;
7890       }
7891       // add nodes of face starting from last node of link
7892       while ( anIter->more() ) {
7893         poly_nodes[iNode++] = cast2Node(anIter->next());
7894       }
7895     }
7896     else {
7897       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7898       while ( nodeIt->more() && !isFLN ) {
7899         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7900         poly_nodes[iNode++] = n;
7901         if (n == nodes[il1]) {
7902           isFLN = true;
7903         }
7904       }
7905       // add nodes to insert
7906       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7907       for (; nIt != aNodesToInsert.end(); nIt++) {
7908         poly_nodes[iNode++] = *nIt;
7909       }
7910       // add nodes of face starting from last node of link
7911       while ( nodeIt->more() ) {
7912         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7913         poly_nodes[iNode++] = n;
7914       }
7915     }
7916
7917     // edit or replace the face
7918     SMESHDS_Mesh *aMesh = GetMeshDS();
7919
7920     if (theFace->IsPoly()) {
7921       aMesh->ChangePolygonNodes(theFace, poly_nodes);
7922     }
7923     else {
7924       int aShapeId = FindShape( theFace );
7925
7926       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7927       myLastCreatedElems.Append(newElem);
7928       if ( aShapeId && newElem )
7929         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7930
7931       aMesh->RemoveElement(theFace);
7932     }
7933     return;
7934   }
7935
7936   SMESHDS_Mesh *aMesh = GetMeshDS();
7937   if( !theFace->IsQuadratic() ) {
7938
7939     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
7940     int nbLinkNodes = 2 + aNodesToInsert.size();
7941     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
7942     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
7943     linkNodes[ 0 ] = nodes[ il1 ];
7944     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
7945     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7946     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7947       linkNodes[ iNode++ ] = *nIt;
7948     }
7949     // decide how to split a quadrangle: compare possible variants
7950     // and choose which of splits to be a quadrangle
7951     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
7952     if ( nbFaceNodes == 3 ) {
7953       iBestQuad = nbSplits;
7954       i4 = i3;
7955     }
7956     else if ( nbFaceNodes == 4 ) {
7957       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
7958       double aBestRate = DBL_MAX;
7959       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
7960         i1 = 0; i2 = 1;
7961         double aBadRate = 0;
7962         // evaluate elements quality
7963         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
7964           if ( iSplit == iQuad ) {
7965             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
7966                                    linkNodes[ i2++ ],
7967                                    nodes[ i3 ],
7968                                    nodes[ i4 ]);
7969             aBadRate += getBadRate( &quad, aCrit );
7970           }
7971           else {
7972             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
7973                                    linkNodes[ i2++ ],
7974                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
7975             aBadRate += getBadRate( &tria, aCrit );
7976           }
7977         }
7978         // choice
7979         if ( aBadRate < aBestRate ) {
7980           iBestQuad = iQuad;
7981           aBestRate = aBadRate;
7982         }
7983       }
7984     }
7985
7986     // create new elements
7987     int aShapeId = FindShape( theFace );
7988
7989     i1 = 0; i2 = 1;
7990     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
7991       SMDS_MeshElement* newElem = 0;
7992       if ( iSplit == iBestQuad )
7993         newElem = aMesh->AddFace (linkNodes[ i1++ ],
7994                                   linkNodes[ i2++ ],
7995                                   nodes[ i3 ],
7996                                   nodes[ i4 ]);
7997       else
7998         newElem = aMesh->AddFace (linkNodes[ i1++ ],
7999                                   linkNodes[ i2++ ],
8000                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8001       myLastCreatedElems.Append(newElem);
8002       if ( aShapeId && newElem )
8003         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8004     }
8005
8006     // change nodes of theFace
8007     const SMDS_MeshNode* newNodes[ 4 ];
8008     newNodes[ 0 ] = linkNodes[ i1 ];
8009     newNodes[ 1 ] = linkNodes[ i2 ];
8010     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8011     newNodes[ 3 ] = nodes[ i4 ];
8012     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8013     const SMDS_MeshElement* newElem = 0;
8014     if (iSplit == iBestQuad)
8015       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8016     else
8017       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8018     myLastCreatedElems.Append(newElem);
8019     if ( aShapeId && newElem )
8020       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8021 } // end if(!theFace->IsQuadratic())
8022   else { // theFace is quadratic
8023     // we have to split theFace on simple triangles and one simple quadrangle
8024     int tmp = il1/2;
8025     int nbshift = tmp*2;
8026     // shift nodes in nodes[] by nbshift
8027     int i,j;
8028     for(i=0; i<nbshift; i++) {
8029       const SMDS_MeshNode* n = nodes[0];
8030       for(j=0; j<nbFaceNodes-1; j++) {
8031         nodes[j] = nodes[j+1];
8032       }
8033       nodes[nbFaceNodes-1] = n;
8034     }
8035     il1 = il1 - nbshift;
8036     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8037     //   n0      n1     n2    n0      n1     n2
8038     //     +-----+-----+        +-----+-----+
8039     //      \         /         |           |
8040     //       \       /          |           |
8041     //      n5+     +n3       n7+           +n3
8042     //         \   /            |           |
8043     //          \ /             |           |
8044     //           +              +-----+-----+
8045     //           n4           n6      n5     n4
8046
8047     // create new elements
8048     int aShapeId = FindShape( theFace );
8049
8050     int n1,n2,n3;
8051     if(nbFaceNodes==6) { // quadratic triangle
8052       SMDS_MeshElement* newElem =
8053         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8054       myLastCreatedElems.Append(newElem);
8055       if ( aShapeId && newElem )
8056         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8057       if(theFace->IsMediumNode(nodes[il1])) {
8058         // create quadrangle
8059         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8060         myLastCreatedElems.Append(newElem);
8061         if ( aShapeId && newElem )
8062           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8063         n1 = 1;
8064         n2 = 2;
8065         n3 = 3;
8066       }
8067       else {
8068         // create quadrangle
8069         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8070         myLastCreatedElems.Append(newElem);
8071         if ( aShapeId && newElem )
8072           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8073         n1 = 0;
8074         n2 = 1;
8075         n3 = 5;
8076       }
8077     }
8078     else { // nbFaceNodes==8 - quadratic quadrangle
8079       SMDS_MeshElement* newElem =
8080         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8081       myLastCreatedElems.Append(newElem);
8082       if ( aShapeId && newElem )
8083         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8084       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8085       myLastCreatedElems.Append(newElem);
8086       if ( aShapeId && newElem )
8087         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8088       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8089       myLastCreatedElems.Append(newElem);
8090       if ( aShapeId && newElem )
8091         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8092       if(theFace->IsMediumNode(nodes[il1])) {
8093         // create quadrangle
8094         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8095         myLastCreatedElems.Append(newElem);
8096         if ( aShapeId && newElem )
8097           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8098         n1 = 1;
8099         n2 = 2;
8100         n3 = 3;
8101       }
8102       else {
8103         // create quadrangle
8104         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8105         myLastCreatedElems.Append(newElem);
8106         if ( aShapeId && newElem )
8107           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8108         n1 = 0;
8109         n2 = 1;
8110         n3 = 7;
8111       }
8112     }
8113     // create needed triangles using n1,n2,n3 and inserted nodes
8114     int nbn = 2 + aNodesToInsert.size();
8115     //const SMDS_MeshNode* aNodes[nbn];
8116     vector<const SMDS_MeshNode*> aNodes(nbn);
8117     aNodes[0] = nodes[n1];
8118     aNodes[nbn-1] = nodes[n2];
8119     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8120     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8121       aNodes[iNode++] = *nIt;
8122     }
8123     for(i=1; i<nbn; i++) {
8124       SMDS_MeshElement* newElem =
8125         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8126       myLastCreatedElems.Append(newElem);
8127       if ( aShapeId && newElem )
8128         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8129     }
8130   }
8131   // remove old face
8132   aMesh->RemoveElement(theFace);
8133 }
8134
8135 //=======================================================================
8136 //function : UpdateVolumes
8137 //purpose  :
8138 //=======================================================================
8139 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8140                                       const SMDS_MeshNode*        theBetweenNode2,
8141                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8142 {
8143   myLastCreatedElems.Clear();
8144   myLastCreatedNodes.Clear();
8145
8146   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8147   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8148     const SMDS_MeshElement* elem = invElemIt->next();
8149
8150     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8151     SMDS_VolumeTool aVolume (elem);
8152     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8153       continue;
8154
8155     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8156     int iface, nbFaces = aVolume.NbFaces();
8157     vector<const SMDS_MeshNode *> poly_nodes;
8158     vector<int> quantities (nbFaces);
8159
8160     for (iface = 0; iface < nbFaces; iface++) {
8161       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8162       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8163       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8164
8165       for (int inode = 0; inode < nbFaceNodes; inode++) {
8166         poly_nodes.push_back(faceNodes[inode]);
8167
8168         if (nbInserted == 0) {
8169           if (faceNodes[inode] == theBetweenNode1) {
8170             if (faceNodes[inode + 1] == theBetweenNode2) {
8171               nbInserted = theNodesToInsert.size();
8172
8173               // add nodes to insert
8174               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8175               for (; nIt != theNodesToInsert.end(); nIt++) {
8176                 poly_nodes.push_back(*nIt);
8177               }
8178             }
8179           }
8180           else if (faceNodes[inode] == theBetweenNode2) {
8181             if (faceNodes[inode + 1] == theBetweenNode1) {
8182               nbInserted = theNodesToInsert.size();
8183
8184               // add nodes to insert in reversed order
8185               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8186               nIt--;
8187               for (; nIt != theNodesToInsert.begin(); nIt--) {
8188                 poly_nodes.push_back(*nIt);
8189               }
8190               poly_nodes.push_back(*nIt);
8191             }
8192           }
8193           else {
8194           }
8195         }
8196       }
8197       quantities[iface] = nbFaceNodes + nbInserted;
8198     }
8199
8200     // Replace or update the volume
8201     SMESHDS_Mesh *aMesh = GetMeshDS();
8202
8203     if (elem->IsPoly()) {
8204       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8205
8206     }
8207     else {
8208       int aShapeId = FindShape( elem );
8209
8210       SMDS_MeshElement* newElem =
8211         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8212       myLastCreatedElems.Append(newElem);
8213       if (aShapeId && newElem)
8214         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8215
8216       aMesh->RemoveElement(elem);
8217     }
8218   }
8219 }
8220
8221 namespace
8222 {
8223   //================================================================================
8224   /*!
8225    * \brief Transform any volume into data of SMDSEntity_Polyhedra
8226    */
8227   //================================================================================
8228
8229   void volumeToPolyhedron( const SMDS_MeshElement*         elem,
8230                            vector<const SMDS_MeshNode *> & nodes,
8231                            vector<int> &                   nbNodeInFaces )
8232   {
8233     nodes.clear();
8234     nbNodeInFaces.clear();
8235     SMDS_VolumeTool vTool ( elem );
8236     for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
8237     {
8238       const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
8239       nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
8240       nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
8241     }
8242   }
8243 }
8244
8245 //=======================================================================
8246 /*!
8247  * \brief Convert elements contained in a submesh to quadratic
8248  * \return int - nb of checked elements
8249  */
8250 //=======================================================================
8251
8252 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8253                                              SMESH_MesherHelper& theHelper,
8254                                              const bool          theForce3d)
8255 {
8256   int nbElem = 0;
8257   if( !theSm ) return nbElem;
8258
8259   vector<int> nbNodeInFaces;
8260   vector<const SMDS_MeshNode *> nodes;
8261   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8262   while(ElemItr->more())
8263   {
8264     nbElem++;
8265     const SMDS_MeshElement* elem = ElemItr->next();
8266     if( !elem ) continue;
8267
8268     // analyse a necessity of conversion
8269     const SMDSAbs_ElementType aType = elem->GetType();
8270     if ( aType < SMDSAbs_Edge || aType > SMDSAbs_Volume )
8271       continue;
8272     const SMDSAbs_EntityType aGeomType = elem->GetEntityType();
8273     bool hasCentralNodes = false;
8274     if ( elem->IsQuadratic() )
8275     {
8276       bool alreadyOK;
8277       switch ( aGeomType ) {
8278       case SMDSEntity_Quad_Triangle:
8279       case SMDSEntity_Quad_Quadrangle:
8280       case SMDSEntity_Quad_Hexa:
8281         alreadyOK = !theHelper.GetIsBiQuadratic(); break;
8282
8283       case SMDSEntity_BiQuad_Triangle:
8284       case SMDSEntity_BiQuad_Quadrangle:
8285       case SMDSEntity_TriQuad_Hexa:
8286         alreadyOK = theHelper.GetIsBiQuadratic();
8287         hasCentralNodes = true;
8288         break;
8289       default:
8290         alreadyOK = true;
8291       }
8292       // take into account already present modium nodes
8293       switch ( aType ) {
8294       case SMDSAbs_Volume:
8295         theHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( elem )); break;
8296       case SMDSAbs_Face:
8297         theHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem )); break;
8298       case SMDSAbs_Edge:
8299         theHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( elem )); break;
8300       default:;
8301       }
8302       if ( alreadyOK )
8303         continue;
8304     }
8305     // get elem data needed to re-create it
8306     //
8307     const int id      = elem->GetID();
8308     const int nbNodes = elem->NbCornerNodes();
8309     nodes.assign(elem->begin_nodes(), elem->end_nodes());
8310     if ( aGeomType == SMDSEntity_Polyhedra )
8311       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
8312     else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
8313       volumeToPolyhedron( elem, nodes, nbNodeInFaces );
8314
8315     // remove a linear element
8316     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
8317
8318     // remove central nodes of biquadratic elements (biquad->quad convertion)
8319     if ( hasCentralNodes )
8320       for ( size_t i = nbNodes * 2; i < nodes.size(); ++i )
8321         if ( nodes[i]->NbInverseElements() == 0 )
8322           GetMeshDS()->RemoveFreeNode( nodes[i], theSm, /*fromGroups=*/true );
8323
8324     const SMDS_MeshElement* NewElem = 0;
8325
8326     switch( aType )
8327     {
8328     case SMDSAbs_Edge :
8329       {
8330         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8331         break;
8332       }
8333     case SMDSAbs_Face :
8334       {
8335         switch(nbNodes)
8336         {
8337         case 3:
8338           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8339           break;
8340         case 4:
8341           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8342           break;
8343         default:
8344           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
8345         }
8346         break;
8347       }
8348     case SMDSAbs_Volume :
8349       {
8350         switch( aGeomType )
8351         {
8352         case SMDSEntity_Tetra:
8353           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8354           break;
8355         case SMDSEntity_Pyramid:
8356           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
8357           break;
8358         case SMDSEntity_Penta:
8359           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
8360           break;
8361         case SMDSEntity_Hexa:
8362         case SMDSEntity_Quad_Hexa:
8363         case SMDSEntity_TriQuad_Hexa:
8364           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8365                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8366           break;
8367         case SMDSEntity_Hexagonal_Prism:
8368         default:
8369           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8370         }
8371         break;
8372       }
8373     default :
8374       continue;
8375     }
8376     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8377     if( NewElem && NewElem->getshapeId() < 1 )
8378       theSm->AddElement( NewElem );
8379   }
8380   return nbElem;
8381 }
8382 //=======================================================================
8383 //function : ConvertToQuadratic
8384 //purpose  :
8385 //=======================================================================
8386
8387 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad)
8388 {
8389   SMESHDS_Mesh* meshDS = GetMeshDS();
8390
8391   SMESH_MesherHelper aHelper(*myMesh);
8392
8393   aHelper.SetIsQuadratic( true );
8394   aHelper.SetIsBiQuadratic( theToBiQuad );
8395   aHelper.SetElementsOnShape(true);
8396
8397   // convert elements assigned to sub-meshes
8398   int nbCheckedElems = 0;
8399   if ( myMesh->HasShapeToMesh() )
8400   {
8401     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8402     {
8403       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8404       while ( smIt->more() ) {
8405         SMESH_subMesh* sm = smIt->next();
8406         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8407           aHelper.SetSubShape( sm->GetSubShape() );
8408           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8409         }
8410       }
8411     }
8412   }
8413
8414   // convert elements NOT assigned to sub-meshes
8415   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8416   if ( nbCheckedElems < totalNbElems ) // not all elements are in sub-meshes
8417   {
8418     aHelper.SetElementsOnShape(false);
8419     SMESHDS_SubMesh *smDS = 0;
8420
8421     // convert edges
8422     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8423     while( aEdgeItr->more() )
8424     {
8425       const SMDS_MeshEdge* edge = aEdgeItr->next();
8426       if ( !edge->IsQuadratic() )
8427       {
8428         int                  id = edge->GetID();
8429         const SMDS_MeshNode* n1 = edge->GetNode(0);
8430         const SMDS_MeshNode* n2 = edge->GetNode(1);
8431
8432         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
8433
8434         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8435         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8436       }
8437       else
8438       {
8439         aHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( edge ));
8440       }
8441     }
8442
8443     // convert faces
8444     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8445     while( aFaceItr->more() )
8446     {
8447       const SMDS_MeshFace* face = aFaceItr->next();
8448       if ( !face ) continue;
8449       
8450       const SMDSAbs_EntityType type = face->GetEntityType();
8451       bool alreadyOK;
8452       switch( type )
8453       {
8454       case SMDSEntity_Quad_Triangle:
8455       case SMDSEntity_Quad_Quadrangle:
8456         alreadyOK = !theToBiQuad;
8457         aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
8458         break;
8459       case SMDSEntity_BiQuad_Triangle:
8460       case SMDSEntity_BiQuad_Quadrangle:
8461         alreadyOK = theToBiQuad;
8462         aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
8463         break;
8464       default: alreadyOK = false;
8465       }
8466       if ( alreadyOK )
8467         continue;
8468
8469       const int id = face->GetID();
8470       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
8471
8472       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
8473
8474       SMDS_MeshFace * NewFace = 0;
8475       switch( type )
8476       {
8477       case SMDSEntity_Triangle:
8478       case SMDSEntity_Quad_Triangle:
8479       case SMDSEntity_BiQuad_Triangle:
8480         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8481         if ( nodes.size() == 7 && nodes[6]->NbInverseElements() == 0 ) // rm a central node
8482           GetMeshDS()->RemoveFreeNode( nodes[6], /*sm=*/0, /*fromGroups=*/true );
8483         break;
8484
8485       case SMDSEntity_Quadrangle:
8486       case SMDSEntity_Quad_Quadrangle:
8487       case SMDSEntity_BiQuad_Quadrangle:
8488         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8489         if ( nodes.size() == 9 && nodes[8]->NbInverseElements() == 0 ) // rm a central node
8490           GetMeshDS()->RemoveFreeNode( nodes[8], /*sm=*/0, /*fromGroups=*/true );
8491         break;
8492
8493       default:;
8494         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
8495       }
8496       ReplaceElemInGroups( face, NewFace, GetMeshDS());
8497     }
8498
8499     // convert volumes
8500     vector<int> nbNodeInFaces;
8501     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8502     while(aVolumeItr->more())
8503     {
8504       const SMDS_MeshVolume* volume = aVolumeItr->next();
8505       if ( !volume ) continue;
8506
8507       const SMDSAbs_EntityType type = volume->GetEntityType();
8508       if (( theToBiQuad  && type == SMDSEntity_TriQuad_Hexa ) ||
8509           ( !theToBiQuad && type == SMDSEntity_Quad_Hexa ))
8510       {
8511         aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume ));
8512         continue;
8513       }
8514       const int id = volume->GetID();
8515       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
8516       if ( type == SMDSEntity_Polyhedra )
8517         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
8518       else if ( type == SMDSEntity_Hexagonal_Prism )
8519         volumeToPolyhedron( volume, nodes, nbNodeInFaces );
8520
8521       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
8522
8523       SMDS_MeshVolume * NewVolume = 0;
8524       switch ( type )
8525       {
8526       case SMDSEntity_Tetra:
8527         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
8528         break;
8529       case SMDSEntity_Hexa:
8530       case SMDSEntity_Quad_Hexa:
8531       case SMDSEntity_TriQuad_Hexa:
8532         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8533                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8534         for ( size_t i = 20; i < nodes.size(); ++i ) // rm central nodes
8535           if ( nodes[i]->NbInverseElements() == 0 )
8536             GetMeshDS()->RemoveFreeNode( nodes[i], /*sm=*/0, /*fromGroups=*/true );
8537         break;
8538       case SMDSEntity_Pyramid:
8539         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8540                                       nodes[3], nodes[4], id, theForce3d);
8541         break;
8542       case SMDSEntity_Penta:
8543         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8544                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
8545         break;
8546       case SMDSEntity_Hexagonal_Prism:
8547       default:
8548         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8549       }
8550       ReplaceElemInGroups(volume, NewVolume, meshDS);
8551     }
8552   }
8553
8554   if ( !theForce3d )
8555   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8556     // aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8557     // aHelper.FixQuadraticElements(myError);
8558     SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
8559   }
8560 }
8561
8562 //================================================================================
8563 /*!
8564  * \brief Makes given elements quadratic
8565  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
8566  *  \param theElements - elements to make quadratic
8567  */
8568 //================================================================================
8569
8570 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
8571                                           TIDSortedElemSet& theElements,
8572                                           const bool        theToBiQuad)
8573 {
8574   if ( theElements.empty() ) return;
8575
8576   // we believe that all theElements are of the same type
8577   const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
8578
8579   // get all nodes shared by theElements
8580   TIDSortedNodeSet allNodes;
8581   TIDSortedElemSet::iterator eIt = theElements.begin();
8582   for ( ; eIt != theElements.end(); ++eIt )
8583     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
8584
8585   // complete theElements with elements of lower dim whose all nodes are in allNodes
8586
8587   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
8588   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
8589   TIDSortedNodeSet::iterator nIt = allNodes.begin();
8590   for ( ; nIt != allNodes.end(); ++nIt )
8591   {
8592     const SMDS_MeshNode* n = *nIt;
8593     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
8594     while ( invIt->more() )
8595     {
8596       const SMDS_MeshElement*      e = invIt->next();
8597       const SMDSAbs_ElementType type = e->GetType();
8598       if ( e->IsQuadratic() )
8599       {
8600         quadAdjacentElems[ type ].insert( e );
8601
8602         bool alreadyOK;
8603         switch ( e->GetEntityType() ) {
8604         case SMDSEntity_Quad_Triangle:
8605         case SMDSEntity_Quad_Quadrangle:
8606         case SMDSEntity_Quad_Hexa:         alreadyOK = !theToBiQuad; break;
8607         case SMDSEntity_BiQuad_Triangle:
8608         case SMDSEntity_BiQuad_Quadrangle:
8609         case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; break;
8610         default:                           alreadyOK = true;
8611         }
8612         if ( alreadyOK )
8613           continue;
8614       }
8615       if ( type >= elemType )
8616         continue; // same type or more complex linear element
8617
8618       if ( !checkedAdjacentElems[ type ].insert( e ).second )
8619         continue; // e is already checked
8620
8621       // check nodes
8622       bool allIn = true;
8623       SMDS_NodeIteratorPtr nodeIt = e->nodeIterator();
8624       while ( nodeIt->more() && allIn )
8625         allIn = allNodes.count( nodeIt->next() );
8626       if ( allIn )
8627         theElements.insert(e );
8628     }
8629   }
8630
8631   SMESH_MesherHelper helper(*myMesh);
8632   helper.SetIsQuadratic( true );
8633   helper.SetIsBiQuadratic( theToBiQuad );
8634
8635   // add links of quadratic adjacent elements to the helper
8636
8637   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
8638     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
8639           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
8640     {
8641       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
8642     }
8643   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
8644     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
8645           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
8646     {
8647       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
8648     }
8649   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
8650     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
8651           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
8652     {
8653       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
8654     }
8655
8656   // make quadratic (or bi-tri-quadratic) elements instead of linear ones
8657
8658   SMESHDS_Mesh*  meshDS = GetMeshDS();
8659   SMESHDS_SubMesh* smDS = 0;
8660   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
8661   {
8662     const SMDS_MeshElement* elem = *eIt;
8663
8664     bool alreadyOK;
8665     int nbCentralNodes = 0;
8666     switch ( elem->GetEntityType() ) {
8667       // linear convertible
8668     case SMDSEntity_Edge:
8669     case SMDSEntity_Triangle:
8670     case SMDSEntity_Quadrangle:
8671     case SMDSEntity_Tetra:
8672     case SMDSEntity_Pyramid:
8673     case SMDSEntity_Hexa:
8674     case SMDSEntity_Penta:             alreadyOK = false;       nbCentralNodes = 0; break;
8675       // quadratic that can become bi-quadratic
8676     case SMDSEntity_Quad_Triangle:
8677     case SMDSEntity_Quad_Quadrangle:
8678     case SMDSEntity_Quad_Hexa:         alreadyOK =!theToBiQuad; nbCentralNodes = 0; break;
8679       // bi-quadratic
8680     case SMDSEntity_BiQuad_Triangle:
8681     case SMDSEntity_BiQuad_Quadrangle: alreadyOK = theToBiQuad; nbCentralNodes = 1; break;
8682     case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; nbCentralNodes = 7; break;
8683       // the rest
8684     default:                           alreadyOK = true;
8685     }
8686     if ( alreadyOK ) continue;
8687
8688     const SMDSAbs_ElementType type = elem->GetType();
8689     const int                   id = elem->GetID();
8690     const int              nbNodes = elem->NbCornerNodes();
8691     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
8692
8693     helper.SetSubShape( elem->getshapeId() );
8694
8695     if ( !smDS || !smDS->Contains( elem ))
8696       smDS = meshDS->MeshElements( elem->getshapeId() );
8697     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
8698
8699     SMDS_MeshElement * newElem = 0;
8700     switch( nbNodes )
8701     {
8702     case 4: // cases for most frequently used element types go first (for optimization)
8703       if ( type == SMDSAbs_Volume )
8704         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8705       else
8706         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8707       break;
8708     case 8:
8709       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8710                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8711       break;
8712     case 3:
8713       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
8714       break;
8715     case 2:
8716       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8717       break;
8718     case 5:
8719       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8720                                  nodes[4], id, theForce3d);
8721       break;
8722     case 6:
8723       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8724                                  nodes[4], nodes[5], id, theForce3d);
8725       break;
8726     default:;
8727     }
8728     ReplaceElemInGroups( elem, newElem, meshDS);
8729     if( newElem && smDS )
8730       smDS->AddElement( newElem );
8731
8732      // remove central nodes
8733     for ( size_t i = nodes.size() - nbCentralNodes; i < nodes.size(); ++i )
8734       if ( nodes[i]->NbInverseElements() == 0 )
8735         meshDS->RemoveFreeNode( nodes[i], smDS, /*fromGroups=*/true );
8736
8737   } // loop on theElements
8738
8739   if ( !theForce3d )
8740   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8741     // helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8742     // helper.FixQuadraticElements( myError );
8743     SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
8744   }
8745 }
8746
8747 //=======================================================================
8748 /*!
8749  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8750  * \return int - nb of checked elements
8751  */
8752 //=======================================================================
8753
8754 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
8755                                      SMDS_ElemIteratorPtr theItr,
8756                                      const int            theShapeID)
8757 {
8758   int nbElem = 0;
8759   SMESHDS_Mesh* meshDS = GetMeshDS();
8760
8761   while( theItr->more() )
8762   {
8763     const SMDS_MeshElement* elem = theItr->next();
8764     nbElem++;
8765     if( elem && elem->IsQuadratic())
8766     {
8767       int id                    = elem->GetID();
8768       int nbCornerNodes         = elem->NbCornerNodes();
8769       SMDSAbs_ElementType aType = elem->GetType();
8770
8771       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
8772
8773       //remove a quadratic element
8774       if ( !theSm || !theSm->Contains( elem ))
8775         theSm = meshDS->MeshElements( elem->getshapeId() );
8776       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
8777
8778       // remove medium nodes
8779       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
8780         if ( nodes[i]->NbInverseElements() == 0 )
8781           meshDS->RemoveFreeNode( nodes[i], theSm );
8782
8783       // add a linear element
8784       nodes.resize( nbCornerNodes );
8785       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
8786       ReplaceElemInGroups(elem, newElem, meshDS);
8787       if( theSm && newElem )
8788         theSm->AddElement( newElem );
8789     }
8790   }
8791   return nbElem;
8792 }
8793
8794 //=======================================================================
8795 //function : ConvertFromQuadratic
8796 //purpose  :
8797 //=======================================================================
8798
8799 bool SMESH_MeshEditor::ConvertFromQuadratic()
8800 {
8801   int nbCheckedElems = 0;
8802   if ( myMesh->HasShapeToMesh() )
8803   {
8804     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8805     {
8806       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8807       while ( smIt->more() ) {
8808         SMESH_subMesh* sm = smIt->next();
8809         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8810           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8811       }
8812     }
8813   }
8814
8815   int totalNbElems =
8816     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8817   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8818   {
8819     SMESHDS_SubMesh *aSM = 0;
8820     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8821   }
8822
8823   return true;
8824 }
8825
8826 namespace
8827 {
8828   //================================================================================
8829   /*!
8830    * \brief Return true if all medium nodes of the element are in the node set
8831    */
8832   //================================================================================
8833
8834   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
8835   {
8836     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
8837       if ( !nodeSet.count( elem->GetNode(i) ))
8838         return false;
8839     return true;
8840   }
8841 }
8842
8843 //================================================================================
8844 /*!
8845  * \brief Makes given elements linear
8846  */
8847 //================================================================================
8848
8849 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
8850 {
8851   if ( theElements.empty() ) return;
8852
8853   // collect IDs of medium nodes of theElements; some of these nodes will be removed
8854   set<int> mediumNodeIDs;
8855   TIDSortedElemSet::iterator eIt = theElements.begin();
8856   for ( ; eIt != theElements.end(); ++eIt )
8857   {
8858     const SMDS_MeshElement* e = *eIt;
8859     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
8860       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
8861   }
8862
8863   // replace given elements by linear ones
8864   SMDS_ElemIteratorPtr elemIt = elemSetIterator( theElements );
8865   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
8866
8867   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
8868   // except those elements sharing medium nodes of quadratic element whose medium nodes
8869   // are not all in mediumNodeIDs
8870
8871   // get remaining medium nodes
8872   TIDSortedNodeSet mediumNodes;
8873   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
8874   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
8875     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
8876       mediumNodes.insert( mediumNodes.end(), n );
8877
8878   // find more quadratic elements to convert
8879   TIDSortedElemSet moreElemsToConvert;
8880   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
8881   for ( ; nIt != mediumNodes.end(); ++nIt )
8882   {
8883     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
8884     while ( invIt->more() )
8885     {
8886       const SMDS_MeshElement* e = invIt->next();
8887       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
8888       {
8889         // find a more complex element including e and
8890         // whose medium nodes are not in mediumNodes
8891         bool complexFound = false;
8892         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
8893         {
8894           SMDS_ElemIteratorPtr invIt2 =
8895             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
8896           while ( invIt2->more() )
8897           {
8898             const SMDS_MeshElement* eComplex = invIt2->next();
8899             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
8900             {
8901               int nbCommonNodes = SMESH_MeshAlgos::GetCommonNodes( e, eComplex ).size();
8902               if ( nbCommonNodes == e->NbNodes())
8903               {
8904                 complexFound = true;
8905                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
8906                 break;
8907               }
8908             }
8909           }
8910         }
8911         if ( !complexFound )
8912           moreElemsToConvert.insert( e );
8913       }
8914     }
8915   }
8916   elemIt = elemSetIterator( moreElemsToConvert );
8917   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
8918 }
8919
8920 //=======================================================================
8921 //function : SewSideElements
8922 //purpose  :
8923 //=======================================================================
8924
8925 SMESH_MeshEditor::Sew_Error
8926 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
8927                                    TIDSortedElemSet&    theSide2,
8928                                    const SMDS_MeshNode* theFirstNode1,
8929                                    const SMDS_MeshNode* theFirstNode2,
8930                                    const SMDS_MeshNode* theSecondNode1,
8931                                    const SMDS_MeshNode* theSecondNode2)
8932 {
8933   myLastCreatedElems.Clear();
8934   myLastCreatedNodes.Clear();
8935
8936   MESSAGE ("::::SewSideElements()");
8937   if ( theSide1.size() != theSide2.size() )
8938     return SEW_DIFF_NB_OF_ELEMENTS;
8939
8940   Sew_Error aResult = SEW_OK;
8941   // Algo:
8942   // 1. Build set of faces representing each side
8943   // 2. Find which nodes of the side 1 to merge with ones on the side 2
8944   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8945
8946   // =======================================================================
8947   // 1. Build set of faces representing each side:
8948   // =======================================================================
8949   // a. build set of nodes belonging to faces
8950   // b. complete set of faces: find missing faces whose nodes are in set of nodes
8951   // c. create temporary faces representing side of volumes if correspondent
8952   //    face does not exist
8953
8954   SMESHDS_Mesh* aMesh = GetMeshDS();
8955   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
8956   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
8957   TIDSortedElemSet             faceSet1, faceSet2;
8958   set<const SMDS_MeshElement*> volSet1,  volSet2;
8959   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
8960   TIDSortedElemSet             * faceSetPtr[] = { &faceSet1, &faceSet2 };
8961   set<const SMDS_MeshElement*> *  volSetPtr[] = { &volSet1,  &volSet2  };
8962   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
8963   TIDSortedElemSet             * elemSetPtr[] = { &theSide1, &theSide2 };
8964   int iSide, iFace, iNode;
8965
8966   list<const SMDS_MeshElement* > tempFaceList;
8967   for ( iSide = 0; iSide < 2; iSide++ ) {
8968     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
8969     TIDSortedElemSet             * elemSet = elemSetPtr[ iSide ];
8970     TIDSortedElemSet             * faceSet = faceSetPtr[ iSide ];
8971     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
8972     set<const SMDS_MeshElement*>::iterator vIt;
8973     TIDSortedElemSet::iterator eIt;
8974     set<const SMDS_MeshNode*>::iterator    nIt;
8975
8976     // check that given nodes belong to given elements
8977     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
8978     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
8979     int firstIndex = -1, secondIndex = -1;
8980     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8981       const SMDS_MeshElement* elem = *eIt;
8982       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
8983       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
8984       if ( firstIndex > -1 && secondIndex > -1 ) break;
8985     }
8986     if ( firstIndex < 0 || secondIndex < 0 ) {
8987       // we can simply return until temporary faces created
8988       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
8989     }
8990
8991     // -----------------------------------------------------------
8992     // 1a. Collect nodes of existing faces
8993     //     and build set of face nodes in order to detect missing
8994     //     faces corresponding to sides of volumes
8995     // -----------------------------------------------------------
8996
8997     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
8998
8999     // loop on the given element of a side
9000     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9001       //const SMDS_MeshElement* elem = *eIt;
9002       const SMDS_MeshElement* elem = *eIt;
9003       if ( elem->GetType() == SMDSAbs_Face ) {
9004         faceSet->insert( elem );
9005         set <const SMDS_MeshNode*> faceNodeSet;
9006         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9007         while ( nodeIt->more() ) {
9008           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9009           nodeSet->insert( n );
9010           faceNodeSet.insert( n );
9011         }
9012         setOfFaceNodeSet.insert( faceNodeSet );
9013       }
9014       else if ( elem->GetType() == SMDSAbs_Volume )
9015         volSet->insert( elem );
9016     }
9017     // ------------------------------------------------------------------------------
9018     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9019     // ------------------------------------------------------------------------------
9020
9021     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9022       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9023       while ( fIt->more() ) { // loop on faces sharing a node
9024         const SMDS_MeshElement* f = fIt->next();
9025         if ( faceSet->find( f ) == faceSet->end() ) {
9026           // check if all nodes are in nodeSet and
9027           // complete setOfFaceNodeSet if they are
9028           set <const SMDS_MeshNode*> faceNodeSet;
9029           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9030           bool allInSet = true;
9031           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9032             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9033             if ( nodeSet->find( n ) == nodeSet->end() )
9034               allInSet = false;
9035             else
9036               faceNodeSet.insert( n );
9037           }
9038           if ( allInSet ) {
9039             faceSet->insert( f );
9040             setOfFaceNodeSet.insert( faceNodeSet );
9041           }
9042         }
9043       }
9044     }
9045
9046     // -------------------------------------------------------------------------
9047     // 1c. Create temporary faces representing sides of volumes if correspondent
9048     //     face does not exist
9049     // -------------------------------------------------------------------------
9050
9051     if ( !volSet->empty() ) {
9052       //int nodeSetSize = nodeSet->size();
9053
9054       // loop on given volumes
9055       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9056         SMDS_VolumeTool vol (*vIt);
9057         // loop on volume faces: find free faces
9058         // --------------------------------------
9059         list<const SMDS_MeshElement* > freeFaceList;
9060         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9061           if ( !vol.IsFreeFace( iFace ))
9062             continue;
9063           // check if there is already a face with same nodes in a face set
9064           const SMDS_MeshElement* aFreeFace = 0;
9065           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9066           int nbNodes = vol.NbFaceNodes( iFace );
9067           set <const SMDS_MeshNode*> faceNodeSet;
9068           vol.GetFaceNodes( iFace, faceNodeSet );
9069           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9070           if ( isNewFace ) {
9071             // no such a face is given but it still can exist, check it
9072             vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
9073             aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
9074           }
9075           if ( !aFreeFace ) {
9076             // create a temporary face
9077             if ( nbNodes == 3 ) {
9078               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9079               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9080             }
9081             else if ( nbNodes == 4 ) {
9082               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9083               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9084             }
9085             else {
9086               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9087               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9088               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9089             }
9090             if ( aFreeFace )
9091               tempFaceList.push_back( aFreeFace );
9092           }
9093
9094           if ( aFreeFace )
9095             freeFaceList.push_back( aFreeFace );
9096
9097         } // loop on faces of a volume
9098
9099         // choose one of several free faces of a volume
9100         // --------------------------------------------
9101         if ( freeFaceList.size() > 1 ) {
9102           // choose a face having max nb of nodes shared by other elems of a side
9103           int maxNbNodes = -1;
9104           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9105           while ( fIt != freeFaceList.end() ) { // loop on free faces
9106             int nbSharedNodes = 0;
9107             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9108             while ( nodeIt->more() ) { // loop on free face nodes
9109               const SMDS_MeshNode* n =
9110                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9111               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9112               while ( invElemIt->more() ) {
9113                 const SMDS_MeshElement* e = invElemIt->next();
9114                 nbSharedNodes += faceSet->count( e );
9115                 nbSharedNodes += elemSet->count( e );
9116               }
9117             }
9118             if ( nbSharedNodes > maxNbNodes ) {
9119               maxNbNodes = nbSharedNodes;
9120               freeFaceList.erase( freeFaceList.begin(), fIt++ );
9121             }
9122             else if ( nbSharedNodes == maxNbNodes ) {
9123               fIt++;
9124             }
9125             else {
9126               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9127             }
9128           }
9129           if ( freeFaceList.size() > 1 )
9130           {
9131             // could not choose one face, use another way
9132             // choose a face most close to the bary center of the opposite side
9133             gp_XYZ aBC( 0., 0., 0. );
9134             set <const SMDS_MeshNode*> addedNodes;
9135             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9136             eIt = elemSet2->begin();
9137             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9138               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9139               while ( nodeIt->more() ) { // loop on free face nodes
9140                 const SMDS_MeshNode* n =
9141                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9142                 if ( addedNodes.insert( n ).second )
9143                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9144               }
9145             }
9146             aBC /= addedNodes.size();
9147             double minDist = DBL_MAX;
9148             fIt = freeFaceList.begin();
9149             while ( fIt != freeFaceList.end() ) { // loop on free faces
9150               double dist = 0;
9151               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9152               while ( nodeIt->more() ) { // loop on free face nodes
9153                 const SMDS_MeshNode* n =
9154                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9155                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9156                 dist += ( aBC - p ).SquareModulus();
9157               }
9158               if ( dist < minDist ) {
9159                 minDist = dist;
9160                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9161               }
9162               else
9163                 fIt = freeFaceList.erase( fIt++ );
9164             }
9165           }
9166         } // choose one of several free faces of a volume
9167
9168         if ( freeFaceList.size() == 1 ) {
9169           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9170           faceSet->insert( aFreeFace );
9171           // complete a node set with nodes of a found free face
9172           //           for ( iNode = 0; iNode < ; iNode++ )
9173           //             nodeSet->insert( fNodes[ iNode ] );
9174         }
9175
9176       } // loop on volumes of a side
9177
9178       //       // complete a set of faces if new nodes in a nodeSet appeared
9179       //       // ----------------------------------------------------------
9180       //       if ( nodeSetSize != nodeSet->size() ) {
9181       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9182       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9183       //           while ( fIt->more() ) { // loop on faces sharing a node
9184       //             const SMDS_MeshElement* f = fIt->next();
9185       //             if ( faceSet->find( f ) == faceSet->end() ) {
9186       //               // check if all nodes are in nodeSet and
9187       //               // complete setOfFaceNodeSet if they are
9188       //               set <const SMDS_MeshNode*> faceNodeSet;
9189       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9190       //               bool allInSet = true;
9191       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9192       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9193       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9194       //                   allInSet = false;
9195       //                 else
9196       //                   faceNodeSet.insert( n );
9197       //               }
9198       //               if ( allInSet ) {
9199       //                 faceSet->insert( f );
9200       //                 setOfFaceNodeSet.insert( faceNodeSet );
9201       //               }
9202       //             }
9203       //           }
9204       //         }
9205       //       }
9206     } // Create temporary faces, if there are volumes given
9207   } // loop on sides
9208
9209   if ( faceSet1.size() != faceSet2.size() ) {
9210     // delete temporary faces: they are in reverseElements of actual nodes
9211 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9212 //    while ( tmpFaceIt->more() )
9213 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9214 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9215 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9216 //      aMesh->RemoveElement(*tmpFaceIt);
9217     MESSAGE("Diff nb of faces");
9218     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9219   }
9220
9221   // ============================================================
9222   // 2. Find nodes to merge:
9223   //              bind a node to remove to a node to put instead
9224   // ============================================================
9225
9226   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9227   if ( theFirstNode1 != theFirstNode2 )
9228     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9229   if ( theSecondNode1 != theSecondNode2 )
9230     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9231
9232   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9233   set< long > linkIdSet; // links to process
9234   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9235
9236   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9237   list< NLink > linkList[2];
9238   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9239   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9240   // loop on links in linkList; find faces by links and append links
9241   // of the found faces to linkList
9242   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9243   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
9244   {
9245     NLink link[] = { *linkIt[0], *linkIt[1] };
9246     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9247     if ( !linkIdSet.count( linkID ) )
9248       continue;
9249
9250     // by links, find faces in the face sets,
9251     // and find indices of link nodes in the found faces;
9252     // in a face set, there is only one or no face sharing a link
9253     // ---------------------------------------------------------------
9254
9255     const SMDS_MeshElement* face[] = { 0, 0 };
9256     vector<const SMDS_MeshNode*> fnodes[2];
9257     int iLinkNode[2][2];
9258     TIDSortedElemSet avoidSet;
9259     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9260       const SMDS_MeshNode* n1 = link[iSide].first;
9261       const SMDS_MeshNode* n2 = link[iSide].second;
9262       //cout << "Side " << iSide << " ";
9263       //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
9264       // find a face by two link nodes
9265       face[ iSide ] = SMESH_MeshAlgos::FindFaceInSet( n1, n2,
9266                                                       *faceSetPtr[ iSide ], avoidSet,
9267                                                       &iLinkNode[iSide][0],
9268                                                       &iLinkNode[iSide][1] );
9269       if ( face[ iSide ])
9270       {
9271         //cout << " F " << face[ iSide]->GetID() <<endl;
9272         faceSetPtr[ iSide ]->erase( face[ iSide ]);
9273         // put face nodes to fnodes
9274         if ( face[ iSide ]->IsQuadratic() )
9275         {
9276           // use interlaced nodes iterator
9277           const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
9278           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9279           SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
9280           while ( nIter->more() )
9281             fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
9282         }
9283         else
9284         {
9285           fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
9286                                   face[ iSide ]->end_nodes() );
9287         }
9288         fnodes[ iSide ].push_back( fnodes[ iSide ].front());
9289       }
9290     }
9291
9292     // check similarity of elements of the sides
9293     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
9294       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9295       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9296         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9297       }
9298       else {
9299         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9300       }
9301       break; // do not return because it's necessary to remove tmp faces
9302     }
9303
9304     // set nodes to merge
9305     // -------------------
9306
9307     if ( face[0] && face[1] )  {
9308       const int nbNodes = face[0]->NbNodes();
9309       if ( nbNodes != face[1]->NbNodes() ) {
9310         MESSAGE("Diff nb of face nodes");
9311         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9312         break; // do not return because it s necessary to remove tmp faces
9313       }
9314       bool reverse[] = { false, false }; // order of nodes in the link
9315       for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9316         // analyse link orientation in faces
9317         int i1 = iLinkNode[ iSide ][ 0 ];
9318         int i2 = iLinkNode[ iSide ][ 1 ];
9319         reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9320       }
9321       int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
9322       int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
9323       for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
9324       {
9325         nReplaceMap.insert  ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
9326                                           fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
9327       }
9328
9329       // add other links of the faces to linkList
9330       // -----------------------------------------
9331
9332       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9333         linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
9334         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9335         if ( !iter_isnew.second ) { // already in a set: no need to process
9336           linkIdSet.erase( iter_isnew.first );
9337         }
9338         else // new in set == encountered for the first time: add
9339         {
9340           const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
9341           const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
9342           linkList[0].push_back ( NLink( n1, n2 ));
9343           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9344         }
9345       }
9346     } // 2 faces found
9347
9348     if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
9349       break;
9350
9351   } // loop on link lists
9352
9353   if ( aResult == SEW_OK &&
9354        ( //linkIt[0] != linkList[0].end() ||
9355          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9356     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9357              " " << (faceSetPtr[1]->empty()));
9358     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9359   }
9360
9361   // ====================================================================
9362   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9363   // ====================================================================
9364
9365   // delete temporary faces
9366 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9367 //  while ( tmpFaceIt->more() )
9368 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9369   list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9370   for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9371     aMesh->RemoveElement(*tmpFaceIt);
9372
9373   if ( aResult != SEW_OK)
9374     return aResult;
9375
9376   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9377   // loop on nodes replacement map
9378   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9379   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9380     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9381       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9382       nodeIDsToRemove.push_back( nToRemove->GetID() );
9383       // loop on elements sharing nToRemove
9384       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9385       while ( invElemIt->more() ) {
9386         const SMDS_MeshElement* e = invElemIt->next();
9387         // get a new suite of nodes: make replacement
9388         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9389         vector< const SMDS_MeshNode*> nodes( nbNodes );
9390         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9391         while ( nIt->more() ) {
9392           const SMDS_MeshNode* n =
9393             static_cast<const SMDS_MeshNode*>( nIt->next() );
9394           nnIt = nReplaceMap.find( n );
9395           if ( nnIt != nReplaceMap.end() ) {
9396             nbReplaced++;
9397             n = (*nnIt).second;
9398           }
9399           nodes[ i++ ] = n;
9400         }
9401         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9402         //         elemIDsToRemove.push_back( e->GetID() );
9403         //       else
9404         if ( nbReplaced )
9405           {
9406             SMDSAbs_ElementType etyp = e->GetType();
9407             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
9408             if (newElem)
9409               {
9410                 myLastCreatedElems.Append(newElem);
9411                 AddToSameGroups(newElem, e, aMesh);
9412                 int aShapeId = e->getshapeId();
9413                 if ( aShapeId )
9414                   {
9415                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
9416                   }
9417               }
9418             aMesh->RemoveElement(e);
9419           }
9420       }
9421     }
9422
9423   Remove( nodeIDsToRemove, true );
9424
9425   return aResult;
9426 }
9427
9428 //================================================================================
9429 /*!
9430  * \brief Find corresponding nodes in two sets of faces
9431  * \param theSide1 - first face set
9432  * \param theSide2 - second first face
9433  * \param theFirstNode1 - a boundary node of set 1
9434  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9435  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9436  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9437  * \param nReplaceMap - output map of corresponding nodes
9438  * \return bool  - is a success or not
9439  */
9440 //================================================================================
9441
9442 #ifdef _DEBUG_
9443 //#define DEBUG_MATCHING_NODES
9444 #endif
9445
9446 SMESH_MeshEditor::Sew_Error
9447 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9448                                     set<const SMDS_MeshElement*>& theSide2,
9449                                     const SMDS_MeshNode*          theFirstNode1,
9450                                     const SMDS_MeshNode*          theFirstNode2,
9451                                     const SMDS_MeshNode*          theSecondNode1,
9452                                     const SMDS_MeshNode*          theSecondNode2,
9453                                     TNodeNodeMap &                nReplaceMap)
9454 {
9455   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9456
9457   nReplaceMap.clear();
9458   if ( theFirstNode1 != theFirstNode2 )
9459     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9460   if ( theSecondNode1 != theSecondNode2 )
9461     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9462
9463   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9464   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9465
9466   list< NLink > linkList[2];
9467   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9468   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9469
9470   // loop on links in linkList; find faces by links and append links
9471   // of the found faces to linkList
9472   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9473   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9474     NLink link[] = { *linkIt[0], *linkIt[1] };
9475     if ( linkSet.find( link[0] ) == linkSet.end() )
9476       continue;
9477
9478     // by links, find faces in the face sets,
9479     // and find indices of link nodes in the found faces;
9480     // in a face set, there is only one or no face sharing a link
9481     // ---------------------------------------------------------------
9482
9483     const SMDS_MeshElement* face[] = { 0, 0 };
9484     list<const SMDS_MeshNode*> notLinkNodes[2];
9485     //bool reverse[] = { false, false }; // order of notLinkNodes
9486     int nbNodes[2];
9487     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9488     {
9489       const SMDS_MeshNode* n1 = link[iSide].first;
9490       const SMDS_MeshNode* n2 = link[iSide].second;
9491       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9492       set< const SMDS_MeshElement* > facesOfNode1;
9493       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9494       {
9495         // during a loop of the first node, we find all faces around n1,
9496         // during a loop of the second node, we find one face sharing both n1 and n2
9497         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9498         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9499         while ( fIt->more() ) { // loop on faces sharing a node
9500           const SMDS_MeshElement* f = fIt->next();
9501           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9502               ! facesOfNode1.insert( f ).second ) // f encounters twice
9503           {
9504             if ( face[ iSide ] ) {
9505               MESSAGE( "2 faces per link " );
9506               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9507             }
9508             face[ iSide ] = f;
9509             faceSet->erase( f );
9510
9511             // get not link nodes
9512             int nbN = f->NbNodes();
9513             if ( f->IsQuadratic() )
9514               nbN /= 2;
9515             nbNodes[ iSide ] = nbN;
9516             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9517             int i1 = f->GetNodeIndex( n1 );
9518             int i2 = f->GetNodeIndex( n2 );
9519             int iEnd = nbN, iBeg = -1, iDelta = 1;
9520             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9521             if ( reverse ) {
9522               std::swap( iEnd, iBeg ); iDelta = -1;
9523             }
9524             int i = i2;
9525             while ( true ) {
9526               i += iDelta;
9527               if ( i == iEnd ) i = iBeg + iDelta;
9528               if ( i == i1 ) break;
9529               nodes.push_back ( f->GetNode( i ) );
9530             }
9531           }
9532         }
9533       }
9534     }
9535     // check similarity of elements of the sides
9536     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9537       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9538       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9539         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9540       }
9541       else {
9542         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9543       }
9544     }
9545
9546     // set nodes to merge
9547     // -------------------
9548
9549     if ( face[0] && face[1] )  {
9550       if ( nbNodes[0] != nbNodes[1] ) {
9551         MESSAGE("Diff nb of face nodes");
9552         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9553       }
9554 #ifdef DEBUG_MATCHING_NODES
9555       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9556                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9557                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9558 #endif
9559       int nbN = nbNodes[0];
9560       {
9561         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9562         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9563         for ( int i = 0 ; i < nbN - 2; ++i ) {
9564 #ifdef DEBUG_MATCHING_NODES
9565           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9566 #endif
9567           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9568         }
9569       }
9570
9571       // add other links of the face 1 to linkList
9572       // -----------------------------------------
9573
9574       const SMDS_MeshElement* f0 = face[0];
9575       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9576       for ( int i = 0; i < nbN; i++ )
9577       {
9578         const SMDS_MeshNode* n2 = f0->GetNode( i );
9579         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9580           linkSet.insert( SMESH_TLink( n1, n2 ));
9581         if ( !iter_isnew.second ) { // already in a set: no need to process
9582           linkSet.erase( iter_isnew.first );
9583         }
9584         else // new in set == encountered for the first time: add
9585         {
9586 #ifdef DEBUG_MATCHING_NODES
9587           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9588                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9589 #endif
9590           linkList[0].push_back ( NLink( n1, n2 ));
9591           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9592         }
9593         n1 = n2;
9594       }
9595     } // 2 faces found
9596   } // loop on link lists
9597
9598   return SEW_OK;
9599 }
9600
9601 //================================================================================
9602 /*!
9603  * \brief Create elements equal (on same nodes) to given ones
9604  *  \param [in] theElements - a set of elems to duplicate. If it is empty, all
9605  *              elements of the uppest dimension are duplicated.
9606  */
9607 //================================================================================
9608
9609 void SMESH_MeshEditor::DoubleElements( const TIDSortedElemSet& theElements )
9610 {
9611   CrearLastCreated();
9612   SMESHDS_Mesh* mesh = GetMeshDS();
9613
9614   // get an element type and an iterator over elements
9615
9616   SMDSAbs_ElementType type;
9617   SMDS_ElemIteratorPtr elemIt;
9618   vector< const SMDS_MeshElement* > allElems;
9619   if ( theElements.empty() )
9620   {
9621     if ( mesh->NbNodes() == 0 )
9622       return;
9623     // get most complex type
9624     SMDSAbs_ElementType types[SMDSAbs_NbElementTypes] = {
9625       SMDSAbs_Volume, SMDSAbs_Face, SMDSAbs_Edge,
9626       SMDSAbs_0DElement, SMDSAbs_Ball, SMDSAbs_Node
9627     };
9628     for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
9629       if ( mesh->GetMeshInfo().NbElements( types[i] ))
9630       {
9631         type = types[i];
9632         break;
9633       }
9634     // put all elements in the vector <allElems>
9635     allElems.reserve( mesh->GetMeshInfo().NbElements( type ));
9636     elemIt = mesh->elementsIterator( type );
9637     while ( elemIt->more() )
9638       allElems.push_back( elemIt->next());
9639     elemIt = elemSetIterator( allElems );
9640   }
9641   else
9642   {
9643     type = (*theElements.begin())->GetType();
9644     elemIt = elemSetIterator( theElements );
9645   }
9646
9647   // duplicate elements
9648
9649   if ( type == SMDSAbs_Ball )
9650   {
9651     SMDS_UnstructuredGrid* vtkGrid = mesh->getGrid();
9652     while ( elemIt->more() )
9653     {
9654       const SMDS_MeshElement* elem = elemIt->next();
9655       if ( elem->GetType() != SMDSAbs_Ball )
9656         continue;
9657       if (( elem = mesh->AddBall( elem->GetNode(0),
9658                                   vtkGrid->GetBallDiameter( elem->getVtkId() ))))
9659         myLastCreatedElems.Append( elem );
9660     }
9661   }
9662   else
9663   {
9664     vector< const SMDS_MeshNode* > nodes;
9665     while ( elemIt->more() )
9666     {
9667       const SMDS_MeshElement* elem = elemIt->next();
9668       if ( elem->GetType() != type )
9669         continue;
9670
9671       nodes.assign( elem->begin_nodes(), elem->end_nodes() );
9672
9673       if ( type == SMDSAbs_Volume  && elem->GetVtkType() == VTK_POLYHEDRON )
9674       {
9675         std::vector<int> quantities =
9676           static_cast< const SMDS_VtkVolume* >( elem )->GetQuantities();
9677         elem = mesh->AddPolyhedralVolume( nodes, quantities );
9678       }
9679       else
9680       {
9681         AddElement( nodes, type, elem->IsPoly() );
9682         elem = 0; // myLastCreatedElems is already filled
9683       }
9684       if ( elem )
9685         myLastCreatedElems.Append( elem );
9686     }
9687   }
9688 }
9689
9690 //================================================================================
9691 /*!
9692   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9693   \param theElems - the list of elements (edges or faces) to be replicated
9694   The nodes for duplication could be found from these elements
9695   \param theNodesNot - list of nodes to NOT replicate
9696   \param theAffectedElems - the list of elements (cells and edges) to which the
9697   replicated nodes should be associated to.
9698   \return TRUE if operation has been completed successfully, FALSE otherwise
9699 */
9700 //================================================================================
9701
9702 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9703                                     const TIDSortedElemSet& theNodesNot,
9704                                     const TIDSortedElemSet& theAffectedElems )
9705 {
9706   myLastCreatedElems.Clear();
9707   myLastCreatedNodes.Clear();
9708
9709   if ( theElems.size() == 0 )
9710     return false;
9711
9712   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9713   if ( !aMeshDS )
9714     return false;
9715
9716   bool res = false;
9717   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9718   // duplicate elements and nodes
9719   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9720   // replce nodes by duplications
9721   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9722   return res;
9723 }
9724
9725 //================================================================================
9726 /*!
9727   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9728   \param theMeshDS - mesh instance
9729   \param theElems - the elements replicated or modified (nodes should be changed)
9730   \param theNodesNot - nodes to NOT replicate
9731   \param theNodeNodeMap - relation of old node to new created node
9732   \param theIsDoubleElem - flag os to replicate element or modify
9733   \return TRUE if operation has been completed successfully, FALSE otherwise
9734 */
9735 //================================================================================
9736
9737 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
9738                                     const TIDSortedElemSet& theElems,
9739                                     const TIDSortedElemSet& theNodesNot,
9740                                     std::map< const SMDS_MeshNode*,
9741                                     const SMDS_MeshNode* >& theNodeNodeMap,
9742                                     const bool theIsDoubleElem )
9743 {
9744   MESSAGE("doubleNodes");
9745   // iterate on through element and duplicate them (by nodes duplication)
9746   bool res = false;
9747   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9748   for ( ;  elemItr != theElems.end(); ++elemItr )
9749   {
9750     const SMDS_MeshElement* anElem = *elemItr;
9751     if (!anElem)
9752       continue;
9753
9754     bool isDuplicate = false;
9755     // duplicate nodes to duplicate element
9756     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9757     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9758     int ind = 0;
9759     while ( anIter->more() )
9760     {
9761
9762       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9763       SMDS_MeshNode* aNewNode = aCurrNode;
9764       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9765         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9766       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9767       {
9768         // duplicate node
9769         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9770         theNodeNodeMap[ aCurrNode ] = aNewNode;
9771         myLastCreatedNodes.Append( aNewNode );
9772       }
9773       isDuplicate |= (aCurrNode != aNewNode);
9774       newNodes[ ind++ ] = aNewNode;
9775     }
9776     if ( !isDuplicate )
9777       continue;
9778
9779     if ( theIsDoubleElem )
9780       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
9781     else
9782       {
9783       MESSAGE("ChangeElementNodes");
9784       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9785       }
9786     res = true;
9787   }
9788   return res;
9789 }
9790
9791 //================================================================================
9792 /*!
9793   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9794   \param theNodes - identifiers of nodes to be doubled
9795   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
9796          nodes. If list of element identifiers is empty then nodes are doubled but
9797          they not assigned to elements
9798   \return TRUE if operation has been completed successfully, FALSE otherwise
9799 */
9800 //================================================================================
9801
9802 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
9803                                     const std::list< int >& theListOfModifiedElems )
9804 {
9805   MESSAGE("DoubleNodes");
9806   myLastCreatedElems.Clear();
9807   myLastCreatedNodes.Clear();
9808
9809   if ( theListOfNodes.size() == 0 )
9810     return false;
9811
9812   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9813   if ( !aMeshDS )
9814     return false;
9815
9816   // iterate through nodes and duplicate them
9817
9818   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9819
9820   std::list< int >::const_iterator aNodeIter;
9821   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9822   {
9823     int aCurr = *aNodeIter;
9824     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9825     if ( !aNode )
9826       continue;
9827
9828     // duplicate node
9829
9830     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9831     if ( aNewNode )
9832     {
9833       anOldNodeToNewNode[ aNode ] = aNewNode;
9834       myLastCreatedNodes.Append( aNewNode );
9835     }
9836   }
9837
9838   // Create map of new nodes for modified elements
9839
9840   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9841
9842   std::list< int >::const_iterator anElemIter;
9843   for ( anElemIter = theListOfModifiedElems.begin();
9844         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9845   {
9846     int aCurr = *anElemIter;
9847     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9848     if ( !anElem )
9849       continue;
9850
9851     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9852
9853     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9854     int ind = 0;
9855     while ( anIter->more() )
9856     {
9857       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9858       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9859       {
9860         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9861         aNodeArr[ ind++ ] = aNewNode;
9862       }
9863       else
9864         aNodeArr[ ind++ ] = aCurrNode;
9865     }
9866     anElemToNodes[ anElem ] = aNodeArr;
9867   }
9868
9869   // Change nodes of elements
9870
9871   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9872     anElemToNodesIter = anElemToNodes.begin();
9873   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9874   {
9875     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9876     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9877     if ( anElem )
9878       {
9879       MESSAGE("ChangeElementNodes");
9880       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9881       }
9882   }
9883
9884   return true;
9885 }
9886
9887 namespace {
9888
9889   //================================================================================
9890   /*!
9891   \brief Check if element located inside shape
9892   \return TRUE if IN or ON shape, FALSE otherwise
9893   */
9894   //================================================================================
9895
9896   template<class Classifier>
9897   bool isInside(const SMDS_MeshElement* theElem,
9898                 Classifier&             theClassifier,
9899                 const double            theTol)
9900   {
9901     gp_XYZ centerXYZ (0, 0, 0);
9902     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9903     while (aNodeItr->more())
9904       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
9905
9906     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9907     theClassifier.Perform(aPnt, theTol);
9908     TopAbs_State aState = theClassifier.State();
9909     return (aState == TopAbs_IN || aState == TopAbs_ON );
9910   }
9911
9912   //================================================================================
9913   /*!
9914    * \brief Classifier of the 3D point on the TopoDS_Face
9915    *        with interaface suitable for isInside()
9916    */
9917   //================================================================================
9918
9919   struct _FaceClassifier
9920   {
9921     Extrema_ExtPS       _extremum;
9922     BRepAdaptor_Surface _surface;
9923     TopAbs_State        _state;
9924
9925     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9926     {
9927       _extremum.Initialize( _surface,
9928                             _surface.FirstUParameter(), _surface.LastUParameter(),
9929                             _surface.FirstVParameter(), _surface.LastVParameter(),
9930                             _surface.Tolerance(), _surface.Tolerance() );
9931     }
9932     void Perform(const gp_Pnt& aPnt, double theTol)
9933     {
9934       _state = TopAbs_OUT;
9935       _extremum.Perform(aPnt);
9936       if ( _extremum.IsDone() )
9937         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9938 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
9939           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9940 #else
9941           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9942 #endif
9943     }
9944     TopAbs_State State() const
9945     {
9946       return _state;
9947     }
9948   };
9949 }
9950
9951 //================================================================================
9952 /*!
9953   \brief Identify the elements that will be affected by node duplication (actual duplication is not performed.
9954   This method is the first step of DoubleNodeElemGroupsInRegion.
9955   \param theElems - list of groups of elements (edges or faces) to be replicated
9956   \param theNodesNot - list of groups of nodes not to replicated
9957   \param theShape - shape to detect affected elements (element which geometric center
9958          located on or inside shape).
9959          The replicated nodes should be associated to affected elements.
9960   \return groups of affected elements
9961   \sa DoubleNodeElemGroupsInRegion()
9962  */
9963 //================================================================================
9964
9965 bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
9966                                                    const TIDSortedElemSet& theNodesNot,
9967                                                    const TopoDS_Shape&     theShape,
9968                                                    TIDSortedElemSet&       theAffectedElems)
9969 {
9970   if ( theShape.IsNull() )
9971     return false;
9972
9973   const double aTol = Precision::Confusion();
9974   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
9975   auto_ptr<_FaceClassifier>              aFaceClassifier;
9976   if ( theShape.ShapeType() == TopAbs_SOLID )
9977   {
9978     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
9979     bsc3d->PerformInfinitePoint(aTol);
9980   }
9981   else if (theShape.ShapeType() == TopAbs_FACE )
9982   {
9983     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
9984   }
9985
9986   // iterates on indicated elements and get elements by back references from their nodes
9987   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9988   for ( ;  elemItr != theElems.end(); ++elemItr )
9989   {
9990     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
9991     if (!anElem)
9992       continue;
9993
9994     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
9995     while ( nodeItr->more() )
9996     {
9997       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
9998       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
9999         continue;
10000       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10001       while ( backElemItr->more() )
10002       {
10003         const SMDS_MeshElement* curElem = backElemItr->next();
10004         if ( curElem && theElems.find(curElem) == theElems.end() &&
10005              ( bsc3d.get() ?
10006                isInside( curElem, *bsc3d, aTol ) :
10007                isInside( curElem, *aFaceClassifier, aTol )))
10008           theAffectedElems.insert( curElem );
10009       }
10010     }
10011   }
10012   return true;
10013 }
10014
10015 //================================================================================
10016 /*!
10017   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10018   \param theElems - group of of elements (edges or faces) to be replicated
10019   \param theNodesNot - group of nodes not to replicate
10020   \param theShape - shape to detect affected elements (element which geometric center
10021   located on or inside shape).
10022   The replicated nodes should be associated to affected elements.
10023   \return TRUE if operation has been completed successfully, FALSE otherwise
10024 */
10025 //================================================================================
10026
10027 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10028                                             const TIDSortedElemSet& theNodesNot,
10029                                             const TopoDS_Shape&     theShape )
10030 {
10031   if ( theShape.IsNull() )
10032     return false;
10033
10034   const double aTol = Precision::Confusion();
10035   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10036   auto_ptr<_FaceClassifier>              aFaceClassifier;
10037   if ( theShape.ShapeType() == TopAbs_SOLID )
10038   {
10039     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10040     bsc3d->PerformInfinitePoint(aTol);
10041   }
10042   else if (theShape.ShapeType() == TopAbs_FACE )
10043   {
10044     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10045   }
10046
10047   // iterates on indicated elements and get elements by back references from their nodes
10048   TIDSortedElemSet anAffected;
10049   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10050   for ( ;  elemItr != theElems.end(); ++elemItr )
10051   {
10052     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10053     if (!anElem)
10054       continue;
10055
10056     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10057     while ( nodeItr->more() )
10058     {
10059       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10060       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10061         continue;
10062       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10063       while ( backElemItr->more() )
10064       {
10065         const SMDS_MeshElement* curElem = backElemItr->next();
10066         if ( curElem && theElems.find(curElem) == theElems.end() &&
10067              ( bsc3d.get() ?
10068                isInside( curElem, *bsc3d, aTol ) :
10069                isInside( curElem, *aFaceClassifier, aTol )))
10070           anAffected.insert( curElem );
10071       }
10072     }
10073   }
10074   return DoubleNodes( theElems, theNodesNot, anAffected );
10075 }
10076
10077 /*!
10078  *  \brief compute an oriented angle between two planes defined by four points.
10079  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10080  *  @param p0 base of the rotation axe
10081  *  @param p1 extremity of the rotation axe
10082  *  @param g1 belongs to the first plane
10083  *  @param g2 belongs to the second plane
10084  */
10085 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10086 {
10087 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10088 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10089 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10090 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10091   gp_Vec vref(p0, p1);
10092   gp_Vec v1(p0, g1);
10093   gp_Vec v2(p0, g2);
10094   gp_Vec n1 = vref.Crossed(v1);
10095   gp_Vec n2 = vref.Crossed(v2);
10096   return n2.AngleWithRef(n1, vref);
10097 }
10098
10099 /*!
10100  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10101  *  The list of groups must contain at least two groups. The groups have to be disjoint: no common element into two different groups.
10102  * The nodes of the internal faces at the boundaries of the groups are doubled. Optionally, the internal faces are replaced by flat elements.
10103  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
10104  * The flat elements are stored in groups of volumes. These groups are named according to the position of the group in the list:
10105  * 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.
10106  * 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.
10107  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
10108  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
10109  * @param theElems - list of groups of volumes, where a group of volume is a set of
10110  * SMDS_MeshElements sorted by Id.
10111  * @param createJointElems - if TRUE, create the elements
10112  * @return TRUE if operation has been completed successfully, FALSE otherwise
10113  */
10114 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10115                                                      bool createJointElems)
10116 {
10117   MESSAGE("----------------------------------------------");
10118   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10119   MESSAGE("----------------------------------------------");
10120
10121   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10122   meshDS->BuildDownWardConnectivity(true);
10123   CHRONO(50);
10124   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10125
10126   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10127   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10128   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10129
10130   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10131   std::map<int,int>celldom; // cell vtkId --> domain
10132   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10133   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10134   faceDomains.clear();
10135   celldom.clear();
10136   cellDomains.clear();
10137   nodeDomains.clear();
10138   std::map<int,int> emptyMap;
10139   std::set<int> emptySet;
10140   emptyMap.clear();
10141
10142   MESSAGE(".. Number of domains :"<<theElems.size());
10143
10144   // Check if the domains do not share an element
10145   for (int idom = 0; idom < theElems.size()-1; idom++)
10146     {
10147 //       MESSAGE("... Check of domain #" << idom);
10148       const TIDSortedElemSet& domain = theElems[idom];
10149       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10150       for (; elemItr != domain.end(); ++elemItr)
10151         {
10152           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10153           int idombisdeb = idom + 1 ;
10154           for (int idombis = idombisdeb; idombis < theElems.size(); idombis++) // check if the element belongs to a domain further in the list
10155           {
10156             const TIDSortedElemSet& domainbis = theElems[idombis];
10157             if ( domainbis.count(anElem) )
10158             {
10159               MESSAGE(".... Domain #" << idom);
10160               MESSAGE(".... Domain #" << idombis);
10161               throw SALOME_Exception("The domains are not disjoint.");
10162               return false ;
10163             }
10164           }
10165         }
10166     }
10167
10168   for (int idom = 0; idom < theElems.size(); idom++)
10169     {
10170
10171       // --- build a map (face to duplicate --> volume to modify)
10172       //     with all the faces shared by 2 domains (group of elements)
10173       //     and corresponding volume of this domain, for each shared face.
10174       //     a volume has a face shared by 2 domains if it has a neighbor which is not in his domain.
10175
10176       MESSAGE("... Neighbors of domain #" << idom);
10177       const TIDSortedElemSet& domain = theElems[idom];
10178       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10179       for (; elemItr != domain.end(); ++elemItr)
10180         {
10181           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10182           if (!anElem)
10183             continue;
10184           int vtkId = anElem->getVtkId();
10185           //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
10186           int neighborsVtkIds[NBMAXNEIGHBORS];
10187           int downIds[NBMAXNEIGHBORS];
10188           unsigned char downTypes[NBMAXNEIGHBORS];
10189           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10190           for (int n = 0; n < nbNeighbors; n++)
10191             {
10192               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10193               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10194               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10195                 {
10196                   bool ok = false ;
10197                   for (int idombis = 0; idombis < theElems.size(); idombis++) // check if the neighbor belongs to another domain of the list
10198                   {
10199                     // MESSAGE("Domain " << idombis);
10200                     const TIDSortedElemSet& domainbis = theElems[idombis];
10201                     if ( domainbis.count(elem)) ok = true ; // neighbor is in a correct domain : face is kept
10202                   }
10203                   if ( ok ) // the characteristics of the face is stored
10204                   {
10205                     DownIdType face(downIds[n], downTypes[n]);
10206                     if (!faceDomains.count(face))
10207                       faceDomains[face] = emptyMap; // create an empty entry for face
10208                     if (!faceDomains[face].count(idom))
10209                       {
10210                         faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10211                         celldom[vtkId] = idom;
10212                         //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
10213                       }
10214                   }
10215                 }
10216             }
10217         }
10218     }
10219
10220   //MESSAGE("Number of shared faces " << faceDomains.size());
10221   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10222
10223   // --- explore the shared faces domain by domain,
10224   //     explore the nodes of the face and see if they belong to a cell in the domain,
10225   //     which has only a node or an edge on the border (not a shared face)
10226
10227   for (int idomain = 0; idomain < theElems.size(); idomain++)
10228     {
10229       //MESSAGE("Domain " << idomain);
10230       const TIDSortedElemSet& domain = theElems[idomain];
10231       itface = faceDomains.begin();
10232       for (; itface != faceDomains.end(); ++itface)
10233         {
10234           std::map<int, int> domvol = itface->second;
10235           if (!domvol.count(idomain))
10236             continue;
10237           DownIdType face = itface->first;
10238           //MESSAGE(" --- face " << face.cellId);
10239           std::set<int> oldNodes;
10240           oldNodes.clear();
10241           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10242           std::set<int>::iterator itn = oldNodes.begin();
10243           for (; itn != oldNodes.end(); ++itn)
10244             {
10245               int oldId = *itn;
10246               //MESSAGE("     node " << oldId);
10247               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10248               for (int i=0; i<l.ncells; i++)
10249                 {
10250                   int vtkId = l.cells[i];
10251                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10252                   if (!domain.count(anElem))
10253                     continue;
10254                   int vtkType = grid->GetCellType(vtkId);
10255                   int downId = grid->CellIdToDownId(vtkId);
10256                   if (downId < 0)
10257                     {
10258                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
10259                       continue; // not OK at this stage of the algorithm:
10260                                 //no cells created after BuildDownWardConnectivity
10261                     }
10262                   DownIdType aCell(downId, vtkType);
10263                   if (!cellDomains.count(aCell))
10264                     cellDomains[aCell] = emptyMap; // create an empty entry for cell
10265                   cellDomains[aCell][idomain] = vtkId;
10266                   celldom[vtkId] = idomain;
10267                   //MESSAGE("       cell " << vtkId << " domain " << idomain);
10268                 }
10269             }
10270         }
10271     }
10272
10273   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10274   //     for each shared face, get the nodes
10275   //     for each node, for each domain of the face, create a clone of the node
10276
10277   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10278   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10279   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
10280
10281   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10282   std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
10283   std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
10284
10285   MESSAGE(".. Duplication of the nodes");
10286   for (int idomain = 0; idomain < theElems.size(); idomain++)
10287     {
10288       itface = faceDomains.begin();
10289       for (; itface != faceDomains.end(); ++itface)
10290         {
10291           std::map<int, int> domvol = itface->second;
10292           if (!domvol.count(idomain))
10293             continue;
10294           DownIdType face = itface->first;
10295           //MESSAGE(" --- face " << face.cellId);
10296           std::set<int> oldNodes;
10297           oldNodes.clear();
10298           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10299           std::set<int>::iterator itn = oldNodes.begin();
10300           for (; itn != oldNodes.end(); ++itn)
10301             {
10302               int oldId = *itn;
10303               //MESSAGE("-+-+-a node " << oldId);
10304               if (!nodeDomains.count(oldId))
10305                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10306               if (nodeDomains[oldId].empty())
10307                 {
10308                   nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
10309                   //MESSAGE("-+-+-b     oldNode " << oldId << " domain " << idomain);
10310                 }
10311               std::map<int, int>::iterator itdom = domvol.begin();
10312               for (; itdom != domvol.end(); ++itdom)
10313                 {
10314                   int idom = itdom->first;
10315                   //MESSAGE("         domain " << idom);
10316                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
10317                     {
10318                       if (nodeDomains[oldId].size() >= 2) // a multiple node
10319                         {
10320                           vector<int> orderedDoms;
10321                           //MESSAGE("multiple node " << oldId);
10322                           if (mutipleNodes.count(oldId))
10323                             orderedDoms = mutipleNodes[oldId];
10324                           else
10325                             {
10326                               map<int,int>::iterator it = nodeDomains[oldId].begin();
10327                               for (; it != nodeDomains[oldId].end(); ++it)
10328                                 orderedDoms.push_back(it->first);
10329                             }
10330                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
10331                           //stringstream txt;
10332                           //for (int i=0; i<orderedDoms.size(); i++)
10333                           //  txt << orderedDoms[i] << " ";
10334                           //MESSAGE("orderedDoms " << txt.str());
10335                           mutipleNodes[oldId] = orderedDoms;
10336                         }
10337                       double *coords = grid->GetPoint(oldId);
10338                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10339                       int newId = newNode->getVtkId();
10340                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
10341                       //MESSAGE("-+-+-c     oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
10342                     }
10343                 }
10344             }
10345         }
10346     }
10347
10348   MESSAGE(".. Creation of elements");
10349   for (int idomain = 0; idomain < theElems.size(); idomain++)
10350     {
10351       itface = faceDomains.begin();
10352       for (; itface != faceDomains.end(); ++itface)
10353         {
10354           std::map<int, int> domvol = itface->second;
10355           if (!domvol.count(idomain))
10356             continue;
10357           DownIdType face = itface->first;
10358           //MESSAGE(" --- face " << face.cellId);
10359           std::set<int> oldNodes;
10360           oldNodes.clear();
10361           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10362           int nbMultipleNodes = 0;
10363           std::set<int>::iterator itn = oldNodes.begin();
10364           for (; itn != oldNodes.end(); ++itn)
10365             {
10366               int oldId = *itn;
10367               if (mutipleNodes.count(oldId))
10368                 nbMultipleNodes++;
10369             }
10370           if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains
10371             {
10372               //MESSAGE("multiple Nodes detected on a shared face");
10373               int downId = itface->first.cellId;
10374               unsigned char cellType = itface->first.cellType;
10375               // --- shared edge or shared face ?
10376               if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
10377                 {
10378                   int nodes[3];
10379                   int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
10380                   for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
10381                     if (mutipleNodes.count(nodes[i]))
10382                       if (!mutipleNodesToFace.count(nodes[i]))
10383                         mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
10384                 }
10385               else // shared face (between two volumes)
10386                 {
10387                   int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
10388                   const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
10389                   const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
10390                   for (int ie =0; ie < nbEdges; ie++)
10391                     {
10392                       int nodes[3];
10393                       int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
10394                       if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
10395                         {
10396                           vector<int> vn0 = mutipleNodes[nodes[0]];
10397                           vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
10398                           vector<int> doms;
10399                           for (int i0 = 0; i0 < vn0.size(); i0++)
10400                             for (int i1 = 0; i1 < vn1.size(); i1++)
10401                               if (vn0[i0] == vn1[i1])
10402                                 doms.push_back(vn0[i0]);
10403                           if (doms.size() >2)
10404                             {
10405                               //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
10406                               double *coords = grid->GetPoint(nodes[0]);
10407                               gp_Pnt p0(coords[0], coords[1], coords[2]);
10408                               coords = grid->GetPoint(nodes[nbNodes - 1]);
10409                               gp_Pnt p1(coords[0], coords[1], coords[2]);
10410                               gp_Pnt gref;
10411                               int vtkVolIds[1000];  // an edge can belong to a lot of volumes
10412                               map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
10413                               map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
10414                               int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
10415                               for (int id=0; id < doms.size(); id++)
10416                                 {
10417                                   int idom = doms[id];
10418                                   for (int ivol=0; ivol<nbvol; ivol++)
10419                                     {
10420                                       int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
10421                                       SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
10422                                       if (theElems[idom].count(elem))
10423                                         {
10424                                           SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
10425                                           domvol[idom] = svol;
10426                                           //MESSAGE("  domain " << idom << " volume " << elem->GetID());
10427                                           double values[3];
10428                                           vtkIdType npts = 0;
10429                                           vtkIdType* pts = 0;
10430                                           grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
10431                                           SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
10432                                           if (id ==0)
10433                                             {
10434                                               gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
10435                                               angleDom[idom] = 0;
10436                                             }
10437                                           else
10438                                             {
10439                                               gp_Pnt g(values[0], values[1], values[2]);
10440                                               angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
10441                                               //MESSAGE("  angle=" << angleDom[idom]);
10442                                             }
10443                                           break;
10444                                         }
10445                                     }
10446                                 }
10447                               map<double, int> sortedDom; // sort domains by angle
10448                               for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
10449                                 sortedDom[ia->second] = ia->first;
10450                               vector<int> vnodes;
10451                               vector<int> vdom;
10452                               for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
10453                                 {
10454                                   vdom.push_back(ib->second);
10455                                   //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
10456                                 }
10457                               for (int ino = 0; ino < nbNodes; ino++)
10458                                 vnodes.push_back(nodes[ino]);
10459                               edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
10460                             }
10461                         }
10462                     }
10463                 }
10464             }
10465         }
10466     }
10467
10468   // --- iterate on shared faces (volumes to modify, face to extrude)
10469   //     get node id's of the face (id SMDS = id VTK)
10470   //     create flat element with old and new nodes if requested
10471
10472   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
10473   //     (domain1 X domain2) = domain1 + MAXINT*domain2
10474
10475   std::map<int, std::map<long,int> > nodeQuadDomains;
10476   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10477
10478   MESSAGE(".. Creation of elements: simple junction");
10479   if (createJointElems)
10480     {
10481       int idg;
10482       string joints2DName = "joints2D";
10483       mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg);
10484       SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
10485       string joints3DName = "joints3D";
10486       mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg);
10487       SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
10488
10489       itface = faceDomains.begin();
10490       for (; itface != faceDomains.end(); ++itface)
10491         {
10492           DownIdType face = itface->first;
10493           std::set<int> oldNodes;
10494           std::set<int>::iterator itn;
10495           oldNodes.clear();
10496           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10497
10498           std::map<int, int> domvol = itface->second;
10499           std::map<int, int>::iterator itdom = domvol.begin();
10500           int dom1 = itdom->first;
10501           int vtkVolId = itdom->second;
10502           itdom++;
10503           int dom2 = itdom->first;
10504           SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
10505                                                              nodeQuadDomains);
10506           stringstream grpname;
10507           grpname << "j_";
10508           if (dom1 < dom2)
10509             grpname << dom1 << "_" << dom2;
10510           else
10511             grpname << dom2 << "_" << dom1;
10512           string namegrp = grpname.str();
10513           if (!mapOfJunctionGroups.count(namegrp))
10514             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
10515           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10516           if (sgrp)
10517             sgrp->Add(vol->GetID());
10518           if (vol->GetType() == SMDSAbs_Volume)
10519             joints3DGrp->Add(vol->GetID());
10520           else if (vol->GetType() == SMDSAbs_Face)
10521             joints2DGrp->Add(vol->GetID());
10522         }
10523     }
10524
10525   // --- create volumes on multiple domain intersection if requested
10526   //     iterate on mutipleNodesToFace
10527   //     iterate on edgesMultiDomains
10528
10529   MESSAGE(".. Creation of elements: multiple junction");
10530   if (createJointElems)
10531     {
10532       // --- iterate on mutipleNodesToFace
10533
10534       std::map<int, std::vector<int> >::iterator itn =  mutipleNodesToFace.begin();
10535       for (; itn != mutipleNodesToFace.end(); ++itn)
10536         {
10537           int node = itn->first;
10538           vector<int> orderDom = itn->second;
10539           vector<vtkIdType> orderedNodes;
10540           for (int idom = 0; idom <orderDom.size(); idom++)
10541             orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
10542             SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
10543
10544             stringstream grpname;
10545             grpname << "m2j_";
10546             grpname << 0 << "_" << 0;
10547             int idg;
10548             string namegrp = grpname.str();
10549             if (!mapOfJunctionGroups.count(namegrp))
10550               mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
10551             SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10552             if (sgrp)
10553               sgrp->Add(face->GetID());
10554         }
10555
10556       // --- iterate on edgesMultiDomains
10557
10558       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
10559       for (; ite != edgesMultiDomains.end(); ++ite)
10560         {
10561           vector<int> nodes = ite->first;
10562           vector<int> orderDom = ite->second;
10563           vector<vtkIdType> orderedNodes;
10564           if (nodes.size() == 2)
10565             {
10566               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
10567               for (int ino=0; ino < nodes.size(); ino++)
10568                 if (orderDom.size() == 3)
10569                   for (int idom = 0; idom <orderDom.size(); idom++)
10570                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
10571                 else
10572                   for (int idom = orderDom.size()-1; idom >=0; idom--)
10573                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
10574               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
10575
10576               int idg;
10577               string namegrp = "jointsMultiples";
10578               if (!mapOfJunctionGroups.count(namegrp))
10579                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
10580               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10581               if (sgrp)
10582                 sgrp->Add(vol->GetID());
10583             }
10584           else
10585             {
10586               INFOS("Quadratic multiple joints not implemented");
10587               // TODO quadratic nodes
10588             }
10589         }
10590     }
10591
10592   // --- list the explicit faces and edges of the mesh that need to be modified,
10593   //     i.e. faces and edges built with one or more duplicated nodes.
10594   //     associate these faces or edges to their corresponding domain.
10595   //     only the first domain found is kept when a face or edge is shared
10596
10597   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
10598   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
10599   faceOrEdgeDom.clear();
10600   feDom.clear();
10601
10602   MESSAGE(".. Modification of elements");
10603   for (int idomain = 0; idomain < theElems.size(); idomain++)
10604     {
10605       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
10606       for (; itnod != nodeDomains.end(); ++itnod)
10607         {
10608           int oldId = itnod->first;
10609           //MESSAGE("     node " << oldId);
10610           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10611           for (int i = 0; i < l.ncells; i++)
10612             {
10613               int vtkId = l.cells[i];
10614               int vtkType = grid->GetCellType(vtkId);
10615               int downId = grid->CellIdToDownId(vtkId);
10616               if (downId < 0)
10617                 continue; // new cells: not to be modified
10618               DownIdType aCell(downId, vtkType);
10619               int volParents[1000];
10620               int nbvol = grid->GetParentVolumes(volParents, vtkId);
10621               for (int j = 0; j < nbvol; j++)
10622                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
10623                   if (!feDom.count(vtkId))
10624                     {
10625                       feDom[vtkId] = idomain;
10626                       faceOrEdgeDom[aCell] = emptyMap;
10627                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
10628                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
10629                       //        << " type " << vtkType << " downId " << downId);
10630                     }
10631             }
10632         }
10633     }
10634
10635   // --- iterate on shared faces (volumes to modify, face to extrude)
10636   //     get node id's of the face
10637   //     replace old nodes by new nodes in volumes, and update inverse connectivity
10638
10639   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
10640   for (int m=0; m<3; m++)
10641     {
10642       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
10643       itface = (*amap).begin();
10644       for (; itface != (*amap).end(); ++itface)
10645         {
10646           DownIdType face = itface->first;
10647           std::set<int> oldNodes;
10648           std::set<int>::iterator itn;
10649           oldNodes.clear();
10650           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10651           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
10652           std::map<int, int> localClonedNodeIds;
10653
10654           std::map<int, int> domvol = itface->second;
10655           std::map<int, int>::iterator itdom = domvol.begin();
10656           for (; itdom != domvol.end(); ++itdom)
10657             {
10658               int idom = itdom->first;
10659               int vtkVolId = itdom->second;
10660               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
10661               localClonedNodeIds.clear();
10662               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10663                 {
10664                   int oldId = *itn;
10665                   if (nodeDomains[oldId].count(idom))
10666                     {
10667                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10668                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
10669                     }
10670                 }
10671               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10672             }
10673         }
10674     }
10675
10676   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
10677   grid->BuildLinks();
10678
10679   CHRONOSTOP(50);
10680   counters::stats();
10681   return true;
10682 }
10683
10684 /*!
10685  * \brief Double nodes on some external faces and create flat elements.
10686  * Flat elements are mainly used by some types of mechanic calculations.
10687  *
10688  * Each group of the list must be constituted of faces.
10689  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10690  * @param theElems - list of groups of faces, where a group of faces is a set of
10691  * SMDS_MeshElements sorted by Id.
10692  * @return TRUE if operation has been completed successfully, FALSE otherwise
10693  */
10694 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
10695 {
10696   MESSAGE("-------------------------------------------------");
10697   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
10698   MESSAGE("-------------------------------------------------");
10699
10700   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10701
10702   // --- For each group of faces
10703   //     duplicate the nodes, create a flat element based on the face
10704   //     replace the nodes of the faces by their clones
10705
10706   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
10707   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
10708   clonedNodes.clear();
10709   intermediateNodes.clear();
10710   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10711   mapOfJunctionGroups.clear();
10712
10713   for (int idom = 0; idom < theElems.size(); idom++)
10714     {
10715       const TIDSortedElemSet& domain = theElems[idom];
10716       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10717       for (; elemItr != domain.end(); ++elemItr)
10718         {
10719           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10720           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
10721           if (!aFace)
10722             continue;
10723           // MESSAGE("aFace=" << aFace->GetID());
10724           bool isQuad = aFace->IsQuadratic();
10725           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
10726
10727           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
10728
10729           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
10730           while (nodeIt->more())
10731             {
10732               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
10733               bool isMedium = isQuad && (aFace->IsMediumNode(node));
10734               if (isMedium)
10735                 ln2.push_back(node);
10736               else
10737                 ln0.push_back(node);
10738
10739               const SMDS_MeshNode* clone = 0;
10740               if (!clonedNodes.count(node))
10741                 {
10742                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
10743                   clonedNodes[node] = clone;
10744                 }
10745               else
10746                 clone = clonedNodes[node];
10747
10748               if (isMedium)
10749                 ln3.push_back(clone);
10750               else
10751                 ln1.push_back(clone);
10752
10753               const SMDS_MeshNode* inter = 0;
10754               if (isQuad && (!isMedium))
10755                 {
10756                   if (!intermediateNodes.count(node))
10757                     {
10758                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
10759                       intermediateNodes[node] = inter;
10760                     }
10761                   else
10762                     inter = intermediateNodes[node];
10763                   ln4.push_back(inter);
10764                 }
10765             }
10766
10767           // --- extrude the face
10768
10769           vector<const SMDS_MeshNode*> ln;
10770           SMDS_MeshVolume* vol = 0;
10771           vtkIdType aType = aFace->GetVtkType();
10772           switch (aType)
10773           {
10774             case VTK_TRIANGLE:
10775               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
10776               // MESSAGE("vol prism " << vol->GetID());
10777               ln.push_back(ln1[0]);
10778               ln.push_back(ln1[1]);
10779               ln.push_back(ln1[2]);
10780               break;
10781             case VTK_QUAD:
10782               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
10783               // MESSAGE("vol hexa " << vol->GetID());
10784               ln.push_back(ln1[0]);
10785               ln.push_back(ln1[1]);
10786               ln.push_back(ln1[2]);
10787               ln.push_back(ln1[3]);
10788               break;
10789             case VTK_QUADRATIC_TRIANGLE:
10790               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
10791                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
10792               // MESSAGE("vol quad prism " << vol->GetID());
10793               ln.push_back(ln1[0]);
10794               ln.push_back(ln1[1]);
10795               ln.push_back(ln1[2]);
10796               ln.push_back(ln3[0]);
10797               ln.push_back(ln3[1]);
10798               ln.push_back(ln3[2]);
10799               break;
10800             case VTK_QUADRATIC_QUAD:
10801 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
10802 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
10803 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
10804               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
10805                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
10806                                       ln4[0], ln4[1], ln4[2], ln4[3]);
10807               // MESSAGE("vol quad hexa " << vol->GetID());
10808               ln.push_back(ln1[0]);
10809               ln.push_back(ln1[1]);
10810               ln.push_back(ln1[2]);
10811               ln.push_back(ln1[3]);
10812               ln.push_back(ln3[0]);
10813               ln.push_back(ln3[1]);
10814               ln.push_back(ln3[2]);
10815               ln.push_back(ln3[3]);
10816               break;
10817             case VTK_POLYGON:
10818               break;
10819             default:
10820               break;
10821           }
10822
10823           if (vol)
10824             {
10825               stringstream grpname;
10826               grpname << "jf_";
10827               grpname << idom;
10828               int idg;
10829               string namegrp = grpname.str();
10830               if (!mapOfJunctionGroups.count(namegrp))
10831                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
10832               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10833               if (sgrp)
10834                 sgrp->Add(vol->GetID());
10835             }
10836
10837           // --- modify the face
10838
10839           aFace->ChangeNodes(&ln[0], ln.size());
10840         }
10841     }
10842   return true;
10843 }
10844
10845 /*!
10846  *  \brief identify all the elements around a geom shape, get the faces delimiting the hole
10847  *  Build groups of volume to remove, groups of faces to replace on the skin of the object,
10848  *  groups of faces to remove inside the object, (idem edges).
10849  *  Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape)
10850  */
10851 void SMESH_MeshEditor::CreateHoleSkin(double radius,
10852                                       const TopoDS_Shape& theShape,
10853                                       SMESH_NodeSearcher* theNodeSearcher,
10854                                       const char* groupName,
10855                                       std::vector<double>&   nodesCoords,
10856                                       std::vector<std::vector<int> >& listOfListOfNodes)
10857 {
10858   MESSAGE("--------------------------------");
10859   MESSAGE("SMESH_MeshEditor::CreateHoleSkin");
10860   MESSAGE("--------------------------------");
10861
10862   // --- zone of volumes to remove is given :
10863   //     1 either by a geom shape (one or more vertices) and a radius,
10864   //     2 either by a group of nodes (representative of the shape)to use with the radius,
10865   //     3 either by a group of nodes where all the elements build on one of this nodes are to remove,
10866   //     In the case 2, the group of nodes is an external group of nodes from another mesh,
10867   //     In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter),
10868   //     defined by it's name.
10869
10870   SMESHDS_GroupBase* groupDS = 0;
10871   SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups();
10872   while ( groupIt->more() )
10873     {
10874       groupDS = 0;
10875       SMESH_Group * group = groupIt->next();
10876       if ( !group ) continue;
10877       groupDS = group->GetGroupDS();
10878       if ( !groupDS || groupDS->IsEmpty() ) continue;
10879       std::string grpName = group->GetName();
10880       //MESSAGE("grpName=" << grpName);
10881       if (grpName == groupName)
10882         break;
10883       else
10884         groupDS = 0;
10885     }
10886
10887   bool isNodeGroup = false;
10888   bool isNodeCoords = false;
10889   if (groupDS)
10890     {
10891       if (groupDS->GetType() != SMDSAbs_Node)
10892         return;
10893       isNodeGroup = true;     // a group of nodes exists and it is in this mesh
10894     }
10895
10896   if (nodesCoords.size() > 0)
10897     isNodeCoords = true; // a list o nodes given by their coordinates
10898   //MESSAGE("---" << isNodeGroup << " " << isNodeCoords);
10899
10900   // --- define groups to build
10901
10902   int idg; // --- group of SMDS volumes
10903   string grpvName = groupName;
10904   grpvName += "_vol";
10905   SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
10906   if (!grp)
10907     {
10908       MESSAGE("group not created " << grpvName);
10909       return;
10910     }
10911   SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
10912
10913   int idgs; // --- group of SMDS faces on the skin
10914   string grpsName = groupName;
10915   grpsName += "_skin";
10916   SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
10917   if (!grps)
10918     {
10919       MESSAGE("group not created " << grpsName);
10920       return;
10921     }
10922   SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
10923
10924   int idgi; // --- group of SMDS faces internal (several shapes)
10925   string grpiName = groupName;
10926   grpiName += "_internalFaces";
10927   SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
10928   if (!grpi)
10929     {
10930       MESSAGE("group not created " << grpiName);
10931       return;
10932     }
10933   SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
10934
10935   int idgei; // --- group of SMDS faces internal (several shapes)
10936   string grpeiName = groupName;
10937   grpeiName += "_internalEdges";
10938   SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
10939   if (!grpei)
10940     {
10941       MESSAGE("group not created " << grpeiName);
10942       return;
10943     }
10944   SMESHDS_Group *sgrpei = dynamic_cast<SMESHDS_Group*>(grpei->GetGroupDS());
10945
10946   // --- build downward connectivity
10947
10948   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10949   meshDS->BuildDownWardConnectivity(true);
10950   SMDS_UnstructuredGrid* grid = meshDS->getGrid();
10951
10952   // --- set of volumes detected inside
10953
10954   std::set<int> setOfInsideVol;
10955   std::set<int> setOfVolToCheck;
10956
10957   std::vector<gp_Pnt> gpnts;
10958   gpnts.clear();
10959
10960   if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
10961     {
10962       MESSAGE("group of nodes provided");
10963       SMDS_ElemIteratorPtr elemIt = groupDS->GetElements();
10964       while ( elemIt->more() )
10965         {
10966           const SMDS_MeshElement* elem = elemIt->next();
10967           if (!elem)
10968             continue;
10969           const SMDS_MeshNode* node = dynamic_cast<const SMDS_MeshNode*>(elem);
10970           if (!node)
10971             continue;
10972           SMDS_MeshElement* vol = 0;
10973           SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume);
10974           while (volItr->more())
10975             {
10976               vol = (SMDS_MeshElement*)volItr->next();
10977               setOfInsideVol.insert(vol->getVtkId());
10978               sgrp->Add(vol->GetID());
10979             }
10980         }
10981     }
10982   else if (isNodeCoords)
10983     {
10984       MESSAGE("list of nodes coordinates provided");
10985       int i = 0;
10986       int k = 0;
10987       while (i < nodesCoords.size()-2)
10988         {
10989           double x = nodesCoords[i++];
10990           double y = nodesCoords[i++];
10991           double z = nodesCoords[i++];
10992           gp_Pnt p = gp_Pnt(x, y ,z);
10993           gpnts.push_back(p);
10994           MESSAGE("TopoDS_Vertex " << k << " " << p.X() << " " << p.Y() << " " << p.Z());
10995           k++;
10996         }
10997     }
10998   else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius
10999     {
11000       MESSAGE("no group of nodes provided, using vertices from geom shape, and radius");
11001       TopTools_IndexedMapOfShape vertexMap;
11002       TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap );
11003       gp_Pnt p = gp_Pnt(0,0,0);
11004       if (vertexMap.Extent() < 1)
11005         return;
11006
11007       for ( int i = 1; i <= vertexMap.Extent(); ++i )
11008         {
11009           const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i ));
11010           p = BRep_Tool::Pnt(vertex);
11011           gpnts.push_back(p);
11012           MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z());
11013         }
11014     }
11015
11016   if (gpnts.size() > 0)
11017     {
11018       int nodeId = 0;
11019       const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
11020       if (startNode)
11021         nodeId = startNode->GetID();
11022       MESSAGE("nodeId " << nodeId);
11023
11024       double radius2 = radius*radius;
11025       MESSAGE("radius2 " << radius2);
11026
11027       // --- volumes on start node
11028
11029       setOfVolToCheck.clear();
11030       SMDS_MeshElement* startVol = 0;
11031       SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
11032       while (volItr->more())
11033         {
11034           startVol = (SMDS_MeshElement*)volItr->next();
11035           setOfVolToCheck.insert(startVol->getVtkId());
11036         }
11037       if (setOfVolToCheck.empty())
11038         {
11039           MESSAGE("No volumes found");
11040           return;
11041         }
11042
11043       // --- starting with central volumes then their neighbors, check if they are inside
11044       //     or outside the domain, until no more new neighbor volume is inside.
11045       //     Fill the group of inside volumes
11046
11047       std::map<int, double> mapOfNodeDistance2;
11048       mapOfNodeDistance2.clear();
11049       std::set<int> setOfOutsideVol;
11050       while (!setOfVolToCheck.empty())
11051         {
11052           std::set<int>::iterator it = setOfVolToCheck.begin();
11053           int vtkId = *it;
11054           MESSAGE("volume to check,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11055           bool volInside = false;
11056           vtkIdType npts = 0;
11057           vtkIdType* pts = 0;
11058           grid->GetCellPoints(vtkId, npts, pts);
11059           for (int i=0; i<npts; i++)
11060             {
11061               double distance2 = 0;
11062               if (mapOfNodeDistance2.count(pts[i]))
11063                 {
11064                   distance2 = mapOfNodeDistance2[pts[i]];
11065                   MESSAGE("point " << pts[i] << " distance2 " << distance2);
11066                 }
11067               else
11068                 {
11069                   double *coords = grid->GetPoint(pts[i]);
11070                   gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
11071                   distance2 = 1.E40;
11072                   for (int j=0; j<gpnts.size(); j++)
11073                     {
11074                       double d2 = aPoint.SquareDistance(gpnts[j]);
11075                       if (d2 < distance2)
11076                         {
11077                           distance2 = d2;
11078                           if (distance2 < radius2)
11079                             break;
11080                         }
11081                     }
11082                   mapOfNodeDistance2[pts[i]] = distance2;
11083                   MESSAGE("  point "  << pts[i]  << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " <<  coords[2]);
11084                 }
11085               if (distance2 < radius2)
11086                 {
11087                   volInside = true; // one or more nodes inside the domain
11088                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
11089                   break;
11090                 }
11091             }
11092           if (volInside)
11093             {
11094               setOfInsideVol.insert(vtkId);
11095               MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11096               int neighborsVtkIds[NBMAXNEIGHBORS];
11097               int downIds[NBMAXNEIGHBORS];
11098               unsigned char downTypes[NBMAXNEIGHBORS];
11099               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11100               for (int n = 0; n < nbNeighbors; n++)
11101                 if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n]))
11102                   setOfVolToCheck.insert(neighborsVtkIds[n]);
11103             }
11104           else
11105             {
11106               setOfOutsideVol.insert(vtkId);
11107               MESSAGE("  volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11108             }
11109           setOfVolToCheck.erase(vtkId);
11110         }
11111     }
11112
11113   // --- for outside hexahedrons, check if they have more than one neighbor volume inside
11114   //     If yes, add the volume to the inside set
11115
11116   bool addedInside = true;
11117   std::set<int> setOfVolToReCheck;
11118   while (addedInside)
11119     {
11120       MESSAGE(" --------------------------- re check");
11121       addedInside = false;
11122       std::set<int>::iterator itv = setOfInsideVol.begin();
11123       for (; itv != setOfInsideVol.end(); ++itv)
11124         {
11125           int vtkId = *itv;
11126           int neighborsVtkIds[NBMAXNEIGHBORS];
11127           int downIds[NBMAXNEIGHBORS];
11128           unsigned char downTypes[NBMAXNEIGHBORS];
11129           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11130           for (int n = 0; n < nbNeighbors; n++)
11131             if (!setOfInsideVol.count(neighborsVtkIds[n]))
11132               setOfVolToReCheck.insert(neighborsVtkIds[n]);
11133         }
11134       setOfVolToCheck = setOfVolToReCheck;
11135       setOfVolToReCheck.clear();
11136       while  (!setOfVolToCheck.empty())
11137         {
11138           std::set<int>::iterator it = setOfVolToCheck.begin();
11139           int vtkId = *it;
11140           if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON)
11141             {
11142               MESSAGE("volume to recheck,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11143               int countInside = 0;
11144               int neighborsVtkIds[NBMAXNEIGHBORS];
11145               int downIds[NBMAXNEIGHBORS];
11146               unsigned char downTypes[NBMAXNEIGHBORS];
11147               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11148               for (int n = 0; n < nbNeighbors; n++)
11149                 if (setOfInsideVol.count(neighborsVtkIds[n]))
11150                   countInside++;
11151               MESSAGE("countInside " << countInside);
11152               if (countInside > 1)
11153                 {
11154                   MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11155                   setOfInsideVol.insert(vtkId);
11156                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
11157                   addedInside = true;
11158                 }
11159               else
11160                 setOfVolToReCheck.insert(vtkId);
11161             }
11162           setOfVolToCheck.erase(vtkId);
11163         }
11164     }
11165
11166   // --- map of Downward faces at the boundary, inside the global volume
11167   //     map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin)
11168   //     fill group of SMDS faces inside the volume (when several volume shapes)
11169   //     fill group of SMDS faces on the skin of the global volume (if skin)
11170
11171   std::map<DownIdType, int, DownIdCompare> boundaryFaces; // boundary faces inside the volume --> corresponding cell
11172   std::map<DownIdType, int, DownIdCompare> skinFaces;     // faces on the skin of the global volume --> corresponding cell
11173   std::set<int>::iterator it = setOfInsideVol.begin();
11174   for (; it != setOfInsideVol.end(); ++it)
11175     {
11176       int vtkId = *it;
11177       //MESSAGE("  vtkId " << vtkId  << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11178       int neighborsVtkIds[NBMAXNEIGHBORS];
11179       int downIds[NBMAXNEIGHBORS];
11180       unsigned char downTypes[NBMAXNEIGHBORS];
11181       int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true);
11182       for (int n = 0; n < nbNeighbors; n++)
11183         {
11184           int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n]));
11185           if (neighborDim == 3)
11186             {
11187               if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary
11188                 {
11189                   DownIdType face(downIds[n], downTypes[n]);
11190                   boundaryFaces[face] = vtkId;
11191                 }
11192               // if the face between to volumes is in the mesh, get it (internal face between shapes)
11193               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
11194               if (vtkFaceId >= 0)
11195                 {
11196                   sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId));
11197                   // find also the smds edges on this face
11198                   int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]);
11199                   const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]);
11200                   const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]);
11201                   for (int i = 0; i < nbEdges; i++)
11202                     {
11203                       int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]);
11204                       if (vtkEdgeId >= 0)
11205                         sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId));
11206                     }
11207                 }
11208             }
11209           else if (neighborDim == 2) // skin of the volume
11210             {
11211               DownIdType face(downIds[n], downTypes[n]);
11212               skinFaces[face] = vtkId;
11213               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
11214               if (vtkFaceId >= 0)
11215                 sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId));
11216             }
11217         }
11218     }
11219
11220   // --- identify the edges constituting the wire of each subshape on the skin
11221   //     define polylines with the nodes of edges, equivalent to wires
11222   //     project polylines on subshapes, and partition, to get geom faces
11223
11224   std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
11225   std::set<int> emptySet;
11226   emptySet.clear();
11227   std::set<int> shapeIds;
11228
11229   SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
11230   while (itelem->more())
11231     {
11232       const SMDS_MeshElement *elem = itelem->next();
11233       int shapeId = elem->getshapeId();
11234       int vtkId = elem->getVtkId();
11235       if (!shapeIdToVtkIdSet.count(shapeId))
11236         {
11237           shapeIdToVtkIdSet[shapeId] = emptySet;
11238           shapeIds.insert(shapeId);
11239         }
11240       shapeIdToVtkIdSet[shapeId].insert(vtkId);
11241     }
11242
11243   std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
11244   std::set<DownIdType, DownIdCompare> emptyEdges;
11245   emptyEdges.clear();
11246
11247   std::map<int, std::set<int> >::iterator itShape =  shapeIdToVtkIdSet.begin();
11248   for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
11249     {
11250       int shapeId = itShape->first;
11251       MESSAGE(" --- Shape ID --- "<< shapeId);
11252       shapeIdToEdges[shapeId] = emptyEdges;
11253
11254       std::vector<int> nodesEdges;
11255
11256       std::set<int>::iterator its = itShape->second.begin();
11257       for (; its != itShape->second.end(); ++its)
11258         {
11259           int vtkId = *its;
11260           MESSAGE("     " << vtkId);
11261           int neighborsVtkIds[NBMAXNEIGHBORS];
11262           int downIds[NBMAXNEIGHBORS];
11263           unsigned char downTypes[NBMAXNEIGHBORS];
11264           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11265           for (int n = 0; n < nbNeighbors; n++)
11266             {
11267               if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
11268                 continue;
11269               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
11270               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11271               if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
11272                 {
11273                   DownIdType edge(downIds[n], downTypes[n]);
11274                   if (!shapeIdToEdges[shapeId].count(edge))
11275                     {
11276                       shapeIdToEdges[shapeId].insert(edge);
11277                       int vtkNodeId[3];
11278                       int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId);
11279                       nodesEdges.push_back(vtkNodeId[0]);
11280                       nodesEdges.push_back(vtkNodeId[nbNodes-1]);
11281                       MESSAGE("       --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1);
11282                     }
11283                 }
11284             }
11285         }
11286
11287       std::list<int> order;
11288       order.clear();
11289       if (nodesEdges.size() > 0)
11290         {
11291           order.push_back(nodesEdges[0]); MESSAGE("       --- back " << order.back()+1); // SMDS id = VTK id + 1;
11292           nodesEdges[0] = -1;
11293           order.push_back(nodesEdges[1]); MESSAGE("       --- back " << order.back()+1);
11294           nodesEdges[1] = -1; // do not reuse this edge
11295           bool found = true;
11296           while (found)
11297             {
11298               int nodeTofind = order.back(); // try first to push back
11299               int i = 0;
11300               for (i = 0; i<nodesEdges.size(); i++)
11301                 if (nodesEdges[i] == nodeTofind)
11302                   break;
11303               if (i == nodesEdges.size())
11304                 found = false; // no follower found on back
11305               else
11306                 {
11307                   if (i%2) // odd ==> use the previous one
11308                     if (nodesEdges[i-1] < 0)
11309                       found = false;
11310                     else
11311                       {
11312                         order.push_back(nodesEdges[i-1]); MESSAGE("       --- back " << order.back()+1);
11313                         nodesEdges[i-1] = -1;
11314                       }
11315                   else // even ==> use the next one
11316                     if (nodesEdges[i+1] < 0)
11317                       found = false;
11318                     else
11319                       {
11320                         order.push_back(nodesEdges[i+1]); MESSAGE("       --- back " << order.back()+1);
11321                         nodesEdges[i+1] = -1;
11322                       }
11323                 }
11324               if (found)
11325                 continue;
11326               // try to push front
11327               found = true;
11328               nodeTofind = order.front(); // try to push front
11329               for (i = 0; i<nodesEdges.size(); i++)
11330                 if (nodesEdges[i] == nodeTofind)
11331                   break;
11332               if (i == nodesEdges.size())
11333                 {
11334                   found = false; // no predecessor found on front
11335                   continue;
11336                 }
11337               if (i%2) // odd ==> use the previous one
11338                 if (nodesEdges[i-1] < 0)
11339                   found = false;
11340                 else
11341                   {
11342                     order.push_front(nodesEdges[i-1]); MESSAGE("       --- front " << order.front()+1);
11343                     nodesEdges[i-1] = -1;
11344                   }
11345               else // even ==> use the next one
11346                 if (nodesEdges[i+1] < 0)
11347                   found = false;
11348                 else
11349                   {
11350                     order.push_front(nodesEdges[i+1]); MESSAGE("       --- front " << order.front()+1);
11351                     nodesEdges[i+1] = -1;
11352                   }
11353             }
11354         }
11355
11356
11357       std::vector<int> nodes;
11358       nodes.push_back(shapeId);
11359       std::list<int>::iterator itl = order.begin();
11360       for (; itl != order.end(); itl++)
11361         {
11362           nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
11363           MESSAGE("              ordered node " << nodes[nodes.size()-1]);
11364         }
11365       listOfListOfNodes.push_back(nodes);
11366     }
11367
11368   //     partition geom faces with blocFissure
11369   //     mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose)
11370   //     mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose)
11371
11372   return;
11373 }
11374
11375
11376 //================================================================================
11377 /*!
11378  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11379  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11380  * \return TRUE if operation has been completed successfully, FALSE otherwise
11381  */
11382 //================================================================================
11383
11384 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11385 {
11386   // iterates on volume elements and detect all free faces on them
11387   SMESHDS_Mesh* aMesh = GetMeshDS();
11388   if (!aMesh)
11389     return false;
11390   //bool res = false;
11391   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11392   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11393   while(vIt->more())
11394   {
11395     const SMDS_MeshVolume* volume = vIt->next();
11396     SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
11397     vTool.SetExternalNormal();
11398     //const bool isPoly = volume->IsPoly();
11399     const int iQuad = volume->IsQuadratic();
11400     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11401     {
11402       if (!vTool.IsFreeFace(iface))
11403         continue;
11404       nbFree++;
11405       vector<const SMDS_MeshNode *> nodes;
11406       int nbFaceNodes = vTool.NbFaceNodes(iface);
11407       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11408       int inode = 0;
11409       for ( ; inode < nbFaceNodes; inode += iQuad+1)
11410         nodes.push_back(faceNodes[inode]);
11411       if (iQuad) { // add medium nodes
11412         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11413           nodes.push_back(faceNodes[inode]);
11414         if ( nbFaceNodes == 9 ) // bi-quadratic quad
11415           nodes.push_back(faceNodes[8]);
11416       }
11417       // add new face based on volume nodes
11418       if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
11419         nbExisted++;
11420         continue; // face already exsist
11421       }
11422       AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
11423       nbCreated++;
11424     }
11425   }
11426   return ( nbFree==(nbExisted+nbCreated) );
11427 }
11428
11429 namespace
11430 {
11431   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11432   {
11433     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11434       return n;
11435     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11436   }
11437 }
11438 //================================================================================
11439 /*!
11440  * \brief Creates missing boundary elements
11441  *  \param elements - elements whose boundary is to be checked
11442  *  \param dimension - defines type of boundary elements to create
11443  *  \param group - a group to store created boundary elements in
11444  *  \param targetMesh - a mesh to store created boundary elements in
11445  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11446  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
11447  *                                boundary elements will be copied into the targetMesh
11448  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11449  *                                boundary elements will be added into the new group
11450  *  \param aroundElements - if true, elements will be created on boundary of given
11451  *                          elements else, on boundary of the whole mesh.
11452  * \return nb of added boundary elements
11453  */
11454 //================================================================================
11455
11456 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11457                                        Bnd_Dimension           dimension,
11458                                        SMESH_Group*            group/*=0*/,
11459                                        SMESH_Mesh*             targetMesh/*=0*/,
11460                                        bool                    toCopyElements/*=false*/,
11461                                        bool                    toCopyExistingBoundary/*=false*/,
11462                                        bool                    toAddExistingBondary/*= false*/,
11463                                        bool                    aroundElements/*= false*/)
11464 {
11465   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11466   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11467   // hope that all elements are of the same type, do not check them all
11468   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11469     throw SALOME_Exception(LOCALIZED("wrong element type"));
11470
11471   if ( !targetMesh )
11472     toCopyElements = toCopyExistingBoundary = false;
11473
11474   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11475   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11476   int nbAddedBnd = 0;
11477
11478   // editor adding present bnd elements and optionally holding elements to add to the group
11479   SMESH_MeshEditor* presentEditor;
11480   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11481   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11482
11483   SMESH_MesherHelper helper( *myMesh );
11484   const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
11485   SMDS_VolumeTool vTool;
11486   TIDSortedElemSet avoidSet;
11487   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11488   int inode;
11489
11490   typedef vector<const SMDS_MeshNode*> TConnectivity;
11491
11492   SMDS_ElemIteratorPtr eIt;
11493   if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
11494   else                  eIt = elemSetIterator( elements );
11495
11496   while (eIt->more())
11497   {
11498     const SMDS_MeshElement* elem = eIt->next();
11499     const int              iQuad = elem->IsQuadratic();
11500
11501     // ------------------------------------------------------------------------------------
11502     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11503     // ------------------------------------------------------------------------------------
11504     vector<const SMDS_MeshElement*> presentBndElems;
11505     vector<TConnectivity>           missingBndElems;
11506     TConnectivity nodes, elemNodes;
11507     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
11508     {
11509       vTool.SetExternalNormal();
11510       const SMDS_MeshElement* otherVol = 0;
11511       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11512       {
11513         if ( !vTool.IsFreeFace(iface, &otherVol) &&
11514              ( !aroundElements || elements.count( otherVol )))
11515           continue;
11516         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11517         const int    nbFaceNodes = vTool.NbFaceNodes (iface);
11518         if ( missType == SMDSAbs_Edge ) // boundary edges
11519         {
11520           nodes.resize( 2+iQuad );
11521           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11522           {
11523             for ( int j = 0; j < nodes.size(); ++j )
11524               nodes[j] =nn[i+j];
11525             if ( const SMDS_MeshElement* edge =
11526                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11527               presentBndElems.push_back( edge );
11528             else
11529               missingBndElems.push_back( nodes );
11530           }
11531         }
11532         else // boundary face
11533         {
11534           nodes.clear();
11535           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11536             nodes.push_back( nn[inode] ); // add corner nodes
11537           if (iQuad)
11538             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11539               nodes.push_back( nn[inode] ); // add medium nodes
11540           int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
11541           if ( iCenter > 0 )
11542             nodes.push_back( vTool.GetNodes()[ iCenter ] );
11543
11544           if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
11545                                                                SMDSAbs_Face, /*noMedium=*/false ))
11546             presentBndElems.push_back( f );
11547           else
11548             missingBndElems.push_back( nodes );
11549
11550           if ( targetMesh != myMesh )
11551           {
11552             // add 1D elements on face boundary to be added to a new mesh
11553             const SMDS_MeshElement* edge;
11554             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11555             {
11556               if ( iQuad )
11557                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11558               else
11559                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11560               if ( edge && avoidSet.insert( edge ).second )
11561                 presentBndElems.push_back( edge );
11562             }
11563           }
11564         }
11565       }
11566     }
11567     else if ( elem->GetType() == SMDSAbs_Face ) // elem is a face ------------------------
11568     {
11569       avoidSet.clear(), avoidSet.insert( elem );
11570       elemNodes.assign( SMDS_MeshElement::iterator( elem->interlacedNodesElemIterator() ),
11571                         SMDS_MeshElement::iterator() );
11572       elemNodes.push_back( elemNodes[0] );
11573       nodes.resize( 2 + iQuad );
11574       const int nbLinks = elem->NbCornerNodes();
11575       for ( int i = 0, iN = 0; i < nbLinks; i++, iN += 1+iQuad )
11576       {
11577         nodes[0] = elemNodes[iN];
11578         nodes[1] = elemNodes[iN+1+iQuad];
11579         if ( SMESH_MeshAlgos::FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11580           continue; // not free link
11581
11582         if ( iQuad ) nodes[2] = elemNodes[iN+1];
11583         if ( const SMDS_MeshElement* edge =
11584              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11585           presentBndElems.push_back( edge );
11586         else
11587           missingBndElems.push_back( nodes );
11588       }
11589     }
11590
11591     // ---------------------------------
11592     // 2. Add missing boundary elements
11593     // ---------------------------------
11594     if ( targetMesh != myMesh )
11595       // instead of making a map of nodes in this mesh and targetMesh,
11596       // we create nodes with same IDs.
11597       for ( int i = 0; i < missingBndElems.size(); ++i )
11598       {
11599         TConnectivity& srcNodes = missingBndElems[i];
11600         TConnectivity  nodes( srcNodes.size() );
11601         for ( inode = 0; inode < nodes.size(); ++inode )
11602           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11603         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11604                                                                    missType,
11605                                                                    /*noMedium=*/false))
11606           continue;
11607         tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11608         ++nbAddedBnd;
11609       }
11610     else
11611       for ( int i = 0; i < missingBndElems.size(); ++i )
11612       {
11613         TConnectivity& nodes = missingBndElems[i];
11614         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11615                                                                    missType,
11616                                                                    /*noMedium=*/false))
11617           continue;
11618         SMDS_MeshElement* elem =
11619           tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11620         ++nbAddedBnd;
11621
11622         // try to set a new element to a shape
11623         if ( myMesh->HasShapeToMesh() )
11624         {
11625           bool ok = true;
11626           set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
11627           const int nbN = nodes.size() / (iQuad+1 );
11628           for ( inode = 0; inode < nbN && ok; ++inode )
11629           {
11630             pair<int, TopAbs_ShapeEnum> i_stype =
11631               helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
11632             if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
11633               mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
11634           }
11635           if ( ok && mediumShapes.size() > 1 )
11636           {
11637             set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
11638             pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
11639             for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
11640             {
11641               if (( ok = ( stype_i->first != stype_i_0.first )))
11642                 ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
11643                                         aMesh->IndexToShape( stype_i_0.second ));
11644             }
11645           }
11646           if ( ok && mediumShapes.begin()->first == missShapeType )
11647             aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
11648         }
11649       }
11650
11651     // ----------------------------------
11652     // 3. Copy present boundary elements
11653     // ----------------------------------
11654     if ( toCopyExistingBoundary )
11655       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11656       {
11657         const SMDS_MeshElement* e = presentBndElems[i];
11658         TConnectivity nodes( e->NbNodes() );
11659         for ( inode = 0; inode < nodes.size(); ++inode )
11660           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11661         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11662       }
11663     else // store present elements to add them to a group
11664       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11665       {
11666         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11667       }
11668
11669   } // loop on given elements
11670
11671   // ---------------------------------------------
11672   // 4. Fill group with boundary elements
11673   // ---------------------------------------------
11674   if ( group )
11675   {
11676     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11677       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11678         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11679   }
11680   tgtEditor.myLastCreatedElems.Clear();
11681   tgtEditor2.myLastCreatedElems.Clear();
11682
11683   // -----------------------
11684   // 5. Copy given elements
11685   // -----------------------
11686   if ( toCopyElements && targetMesh != myMesh )
11687   {
11688     if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
11689     else                  eIt = elemSetIterator( elements );
11690     while (eIt->more())
11691     {
11692       const SMDS_MeshElement* elem = eIt->next();
11693       TConnectivity nodes( elem->NbNodes() );
11694       for ( inode = 0; inode < nodes.size(); ++inode )
11695         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11696       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11697
11698       tgtEditor.myLastCreatedElems.Clear();
11699     }
11700   }
11701   return nbAddedBnd;
11702 }