Salome HOME
merge from branch BR_SMDS_MEMIMP 29 nov 2010
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 //  Copyright (C) 2007-2010  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 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27 //
28 #define CHRONODEF
29 #include "SMESH_MeshEditor.hxx"
30
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
42
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
45
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
52
53 #include "utilities.h"
54
55 #include <BRepAdaptor_Surface.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 <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
74 #include <TopExp.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
79 #include <TopoDS.hxx>
80 #include <TopoDS_Face.hxx>
81 #include <gp.hxx>
82 #include <gp_Ax1.hxx>
83 #include <gp_Dir.hxx>
84 #include <gp_Lin.hxx>
85 #include <gp_Pln.hxx>
86 #include <gp_Trsf.hxx>
87 #include <gp_Vec.hxx>
88 #include <gp_XY.hxx>
89 #include <gp_XYZ.hxx>
90
91 #include <math.h>
92
93 #include <map>
94 #include <set>
95 #include <numeric>
96 #include <limits>
97
98 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
99
100 using namespace std;
101 using namespace SMESH::Controls;
102
103 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
104 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
105
106 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
107
108 //=======================================================================
109 //function : SMESH_MeshEditor
110 //purpose  :
111 //=======================================================================
112
113 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
114   :myMesh( theMesh ) // theMesh may be NULL
115 {
116 }
117
118 //=======================================================================
119 /*!
120  * \brief Add element
121  */
122 //=======================================================================
123
124 SMDS_MeshElement*
125 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
126                              const SMDSAbs_ElementType            type,
127                              const bool                           isPoly,
128                              const int                            ID)
129 {
130   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
131   SMDS_MeshElement* e = 0;
132   int nbnode = node.size();
133   SMESHDS_Mesh* mesh = GetMeshDS();
134   switch ( type ) {
135   case SMDSAbs_0DElement:
136     if ( nbnode == 1 )
137       if ( ID >= 0 ) e = mesh->Add0DElementWithID(node[0], ID);
138       else      e = mesh->Add0DElement      (node[0] );
139     break;
140   case SMDSAbs_Edge:
141     if ( nbnode == 2 )
142       if ( ID >= 0 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
143       else      e = mesh->AddEdge      (node[0], node[1] );
144     else if ( nbnode == 3 )
145       if ( ID >= 0 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
146       else      e = mesh->AddEdge      (node[0], node[1], node[2] );
147     break;
148   case SMDSAbs_Face:
149     if ( !isPoly ) {
150       if      (nbnode == 3)
151         if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
152         else      e = mesh->AddFace      (node[0], node[1], node[2] );
153       else if (nbnode == 4) 
154         if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
155         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
156       else if (nbnode == 6)
157         if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
158                                           node[4], node[5], ID);
159         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
160                                           node[4], node[5] );
161       else if (nbnode == 8)
162         if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
163                                           node[4], node[5], node[6], node[7], ID);
164         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
165                                           node[4], node[5], node[6], node[7] );
166     } else {
167       if ( ID >= 0 ) e = mesh->AddPolygonalFaceWithID(node, ID);
168       else      e = mesh->AddPolygonalFace      (node    );
169     }
170     break;
171   case SMDSAbs_Volume:
172     if ( !isPoly ) {
173       if      (nbnode == 4)
174         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
175         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
176       else if (nbnode == 5)
177         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
178                                             node[4], ID);
179         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
180                                             node[4] );
181       else if (nbnode == 6)
182         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
183                                             node[4], node[5], ID);
184         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
185                                             node[4], node[5] );
186       else if (nbnode == 8)
187         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
188                                             node[4], node[5], node[6], node[7], ID);
189         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
190                                             node[4], node[5], node[6], node[7] );
191       else if (nbnode == 10)
192         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
193                                             node[4], node[5], node[6], node[7],
194                                             node[8], node[9], ID);
195         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
196                                             node[4], node[5], node[6], node[7],
197                                             node[8], node[9] );
198       else if (nbnode == 13)
199         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
200                                             node[4], node[5], node[6], node[7],
201                                             node[8], node[9], node[10],node[11],
202                                             node[12],ID);
203         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
204                                             node[4], node[5], node[6], node[7],
205                                             node[8], node[9], node[10],node[11],
206                                             node[12] );
207       else if (nbnode == 15)
208         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
209                                             node[4], node[5], node[6], node[7],
210                                             node[8], node[9], node[10],node[11],
211                                             node[12],node[13],node[14],ID);
212         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
213                                             node[4], node[5], node[6], node[7],
214                                             node[8], node[9], node[10],node[11],
215                                             node[12],node[13],node[14] );
216       else if (nbnode == 20)
217         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
218                                             node[4], node[5], node[6], node[7],
219                                             node[8], node[9], node[10],node[11],
220                                             node[12],node[13],node[14],node[15],
221                                             node[16],node[17],node[18],node[19],ID);
222         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
223                                             node[4], node[5], node[6], node[7],
224                                             node[8], node[9], node[10],node[11],
225                                             node[12],node[13],node[14],node[15],
226                                             node[16],node[17],node[18],node[19] );
227     }
228   }
229   if ( e ) myLastCreatedElems.Append( e );
230   return e;
231 }
232
233 //=======================================================================
234 /*!
235  * \brief Add element
236  */
237 //=======================================================================
238
239 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
240                                                const SMDSAbs_ElementType type,
241                                                const bool                isPoly,
242                                                const int                 ID)
243 {
244   vector<const SMDS_MeshNode*> nodes;
245   nodes.reserve( nodeIDs.size() );
246   vector<int>::const_iterator id = nodeIDs.begin();
247   while ( id != nodeIDs.end() ) {
248     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
249       nodes.push_back( node );
250     else
251       return 0;
252   }
253   return AddElement( nodes, type, isPoly, ID );
254 }
255
256 //=======================================================================
257 //function : Remove
258 //purpose  : Remove a node or an element.
259 //           Modify a compute state of sub-meshes which become empty
260 //=======================================================================
261
262 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
263                               const bool         isNodes )
264 {
265   myLastCreatedElems.Clear();
266   myLastCreatedNodes.Clear();
267
268   SMESHDS_Mesh* aMesh = GetMeshDS();
269   set< SMESH_subMesh *> smmap;
270
271   int removed = 0;
272   list<int>::const_iterator it = theIDs.begin();
273   for ( ; it != theIDs.end(); it++ ) {
274     const SMDS_MeshElement * elem;
275     if ( isNodes )
276       elem = aMesh->FindNode( *it );
277     else
278       elem = aMesh->FindElement( *it );
279     if ( !elem )
280       continue;
281
282     // Notify VERTEX sub-meshes about modification
283     if ( isNodes ) {
284       const SMDS_MeshNode* node = cast2Node( elem );
285       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
286         if ( int aShapeID = node->getshapeId() )
287           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
288             smmap.insert( sm );
289     }
290     // Find sub-meshes to notify about modification
291     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
292     //     while ( nodeIt->more() ) {
293     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
294     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
295     //       if ( aPosition.get() ) {
296     //         if ( int aShapeID = aPosition->GetShapeId() ) {
297     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
298     //             smmap.insert( sm );
299     //         }
300     //       }
301     //     }
302
303     // Do remove
304     if ( isNodes )
305       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
306     else
307       aMesh->RemoveElement( elem );
308     removed++;
309   }
310
311   // Notify sub-meshes about modification
312   if ( !smmap.empty() ) {
313     set< SMESH_subMesh *>::iterator smIt;
314     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
315       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
316   }
317
318   //   // Check if the whole mesh becomes empty
319   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
320   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
321
322   return removed;
323 }
324
325 //=======================================================================
326 //function : FindShape
327 //purpose  : Return an index of the shape theElem is on
328 //           or zero if a shape not found
329 //=======================================================================
330
331 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
332 {
333   myLastCreatedElems.Clear();
334   myLastCreatedNodes.Clear();
335
336   SMESHDS_Mesh * aMesh = GetMeshDS();
337   if ( aMesh->ShapeToMesh().IsNull() )
338     return 0;
339
340   if ( theElem->GetType() == SMDSAbs_Node )
341     {
342       int aShapeID = theElem->getshapeId();
343       if (aShapeID <= 0)
344         return 0;
345       else
346         return aShapeID;
347     }
348
349   TopoDS_Shape aShape; // the shape a node is on
350   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
351   while ( nodeIt->more() ) {
352     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
353     int aShapeID = node->getshapeId();
354     if (aShapeID > 0) {
355       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
356       if ( sm ) {
357         if ( sm->Contains( theElem ))
358           return aShapeID;
359         if ( aShape.IsNull() )
360           aShape = aMesh->IndexToShape( aShapeID );
361       }
362       else {
363         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
364       }
365     }
366   }
367
368   // None of nodes is on a proper shape,
369   // find the shape among ancestors of aShape on which a node is
370   if ( aShape.IsNull() ) {
371     //MESSAGE ("::FindShape() - NONE node is on shape")
372     return 0;
373   }
374   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
375   for ( ; ancIt.More(); ancIt.Next() ) {
376     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
377     if ( sm && sm->Contains( theElem ))
378       return aMesh->ShapeToIndex( ancIt.Value() );
379   }
380
381   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
382   return 0;
383 }
384
385 //=======================================================================
386 //function : IsMedium
387 //purpose  :
388 //=======================================================================
389
390 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
391                                 const SMDSAbs_ElementType typeToCheck)
392 {
393   bool isMedium = false;
394   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
395   while (it->more() && !isMedium ) {
396     const SMDS_MeshElement* elem = it->next();
397     isMedium = elem->IsMediumNode(node);
398   }
399   return isMedium;
400 }
401
402 //=======================================================================
403 //function : ShiftNodesQuadTria
404 //purpose  : auxilary
405 //           Shift nodes in the array corresponded to quadratic triangle
406 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
407 //=======================================================================
408 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
409 {
410   const SMDS_MeshNode* nd1 = aNodes[0];
411   aNodes[0] = aNodes[1];
412   aNodes[1] = aNodes[2];
413   aNodes[2] = nd1;
414   const SMDS_MeshNode* nd2 = aNodes[3];
415   aNodes[3] = aNodes[4];
416   aNodes[4] = aNodes[5];
417   aNodes[5] = nd2;
418 }
419
420 //=======================================================================
421 //function : GetNodesFromTwoTria
422 //purpose  : auxilary
423 //           Shift nodes in the array corresponded to quadratic triangle
424 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
425 //=======================================================================
426 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
427                                 const SMDS_MeshElement * theTria2,
428                                 const SMDS_MeshNode* N1[],
429                                 const SMDS_MeshNode* N2[])
430 {
431   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
432   int i=0;
433   while(i<6) {
434     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
435     i++;
436   }
437   if(it->more()) return false;
438   it = theTria2->nodesIterator();
439   i=0;
440   while(i<6) {
441     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
442     i++;
443   }
444   if(it->more()) return false;
445
446   int sames[3] = {-1,-1,-1};
447   int nbsames = 0;
448   int j;
449   for(i=0; i<3; i++) {
450     for(j=0; j<3; j++) {
451       if(N1[i]==N2[j]) {
452         sames[i] = j;
453         nbsames++;
454         break;
455       }
456     }
457   }
458   if(nbsames!=2) return false;
459   if(sames[0]>-1) {
460     ShiftNodesQuadTria(N1);
461     if(sames[1]>-1) {
462       ShiftNodesQuadTria(N1);
463     }
464   }
465   i = sames[0] + sames[1] + sames[2];
466   for(; i<2; i++) {
467     ShiftNodesQuadTria(N2);
468   }
469   // now we receive following N1 and N2 (using numeration as above image)
470   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
471   // i.e. first nodes from both arrays determ new diagonal
472   return true;
473 }
474
475 //=======================================================================
476 //function : InverseDiag
477 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
478 //           but having other common link.
479 //           Return False if args are improper
480 //=======================================================================
481
482 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
483                                     const SMDS_MeshElement * theTria2 )
484 {
485   MESSAGE("InverseDiag");
486   myLastCreatedElems.Clear();
487   myLastCreatedNodes.Clear();
488
489   if (!theTria1 || !theTria2)
490     return false;
491
492   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
493   if (!F1) return false;
494   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
495   if (!F2) return false;
496   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
497       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
498
499     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
500     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
501     //    |/ |                                         | \|
502     //  B +--+ 2                                     B +--+ 2
503
504     // put nodes in array and find out indices of the same ones
505     const SMDS_MeshNode* aNodes [6];
506     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
507     int i = 0;
508     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
509     while ( it->more() ) {
510       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
511
512       if ( i > 2 ) // theTria2
513         // find same node of theTria1
514         for ( int j = 0; j < 3; j++ )
515           if ( aNodes[ i ] == aNodes[ j ]) {
516             sameInd[ j ] = i;
517             sameInd[ i ] = j;
518             break;
519           }
520       // next
521       i++;
522       if ( i == 3 ) {
523         if ( it->more() )
524           return false; // theTria1 is not a triangle
525         it = theTria2->nodesIterator();
526       }
527       if ( i == 6 && it->more() )
528         return false; // theTria2 is not a triangle
529     }
530
531     // find indices of 1,2 and of A,B in theTria1
532     int iA = 0, iB = 0, i1 = 0, i2 = 0;
533     for ( i = 0; i < 6; i++ ) {
534       if ( sameInd [ i ] == 0 )
535         if ( i < 3 ) i1 = i;
536         else         i2 = i;
537       else if (i < 3)
538         if ( iA ) iB = i;
539         else      iA = i;
540     }
541     // nodes 1 and 2 should not be the same
542     if ( aNodes[ i1 ] == aNodes[ i2 ] )
543       return false;
544
545     // theTria1: A->2
546     aNodes[ iA ] = aNodes[ i2 ];
547     // theTria2: B->1
548     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
549
550     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
551     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
552
553     return true;
554
555   } // end if(F1 && F2)
556
557   // check case of quadratic faces
558   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
559     return false;
560   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
561     return false;
562
563   //       5
564   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
565   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
566   //    |   / |
567   //  7 +  +  + 6
568   //    | /9  |
569   //    |/    |
570   //  4 +--+--+ 3
571   //       8
572
573   const SMDS_MeshNode* N1 [6];
574   const SMDS_MeshNode* N2 [6];
575   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
576     return false;
577   // now we receive following N1 and N2 (using numeration as above image)
578   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
579   // i.e. first nodes from both arrays determ new diagonal
580
581   const SMDS_MeshNode* N1new [6];
582   const SMDS_MeshNode* N2new [6];
583   N1new[0] = N1[0];
584   N1new[1] = N2[0];
585   N1new[2] = N2[1];
586   N1new[3] = N1[4];
587   N1new[4] = N2[3];
588   N1new[5] = N1[5];
589   N2new[0] = N1[0];
590   N2new[1] = N1[1];
591   N2new[2] = N2[0];
592   N2new[3] = N1[3];
593   N2new[4] = N2[5];
594   N2new[5] = N1[4];
595   // replaces nodes in faces
596   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
597   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
598
599   return true;
600 }
601
602 //=======================================================================
603 //function : findTriangles
604 //purpose  : find triangles sharing theNode1-theNode2 link
605 //=======================================================================
606
607 static bool findTriangles(const SMDS_MeshNode *    theNode1,
608                           const SMDS_MeshNode *    theNode2,
609                           const SMDS_MeshElement*& theTria1,
610                           const SMDS_MeshElement*& theTria2)
611 {
612   if ( !theNode1 || !theNode2 ) return false;
613
614   theTria1 = theTria2 = 0;
615
616   set< const SMDS_MeshElement* > emap;
617   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
618   while (it->more()) {
619     const SMDS_MeshElement* elem = it->next();
620     if ( elem->NbNodes() == 3 )
621       emap.insert( elem );
622   }
623   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
624   while (it->more()) {
625     const SMDS_MeshElement* elem = it->next();
626     if ( emap.find( elem ) != emap.end() )
627       if ( theTria1 ) {
628         // theTria1 must be element with minimum ID
629         if( theTria1->GetID() < elem->GetID() ) {
630           theTria2 = elem;
631         }
632         else {
633           theTria2 = theTria1;
634           theTria1 = elem;
635         }
636         break;
637       }
638       else {
639         theTria1 = elem;
640       }
641   }
642   return ( theTria1 && theTria2 );
643 }
644
645 //=======================================================================
646 //function : InverseDiag
647 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
648 //           with ones built on the same 4 nodes but having other common link.
649 //           Return false if proper faces not found
650 //=======================================================================
651
652 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
653                                     const SMDS_MeshNode * theNode2)
654 {
655   myLastCreatedElems.Clear();
656   myLastCreatedNodes.Clear();
657
658   MESSAGE( "::InverseDiag()" );
659
660   const SMDS_MeshElement *tr1, *tr2;
661   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
662     return false;
663
664   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
665   if (!F1) return false;
666   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
667   if (!F2) return false;
668   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
669       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
670
671     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
672     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
673     //    |/ |                                    | \|
674     //  B +--+ 2                                B +--+ 2
675
676     // put nodes in array
677     // and find indices of 1,2 and of A in tr1 and of B in tr2
678     int i, iA1 = 0, i1 = 0;
679     const SMDS_MeshNode* aNodes1 [3];
680     SMDS_ElemIteratorPtr it;
681     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
682       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
683       if ( aNodes1[ i ] == theNode1 )
684         iA1 = i; // node A in tr1
685       else if ( aNodes1[ i ] != theNode2 )
686         i1 = i;  // node 1
687     }
688     int iB2 = 0, i2 = 0;
689     const SMDS_MeshNode* aNodes2 [3];
690     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
691       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
692       if ( aNodes2[ i ] == theNode2 )
693         iB2 = i; // node B in tr2
694       else if ( aNodes2[ i ] != theNode1 )
695         i2 = i;  // node 2
696     }
697
698     // nodes 1 and 2 should not be the same
699     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
700       return false;
701
702     // tr1: A->2
703     aNodes1[ iA1 ] = aNodes2[ i2 ];
704     // tr2: B->1
705     aNodes2[ iB2 ] = aNodes1[ i1 ];
706
707     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
708     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
709
710     return true;
711   }
712
713   // check case of quadratic faces
714   return InverseDiag(tr1,tr2);
715 }
716
717 //=======================================================================
718 //function : getQuadrangleNodes
719 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
720 //           fusion of triangles tr1 and tr2 having shared link on
721 //           theNode1 and theNode2
722 //=======================================================================
723
724 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
725                         const SMDS_MeshNode *    theNode1,
726                         const SMDS_MeshNode *    theNode2,
727                         const SMDS_MeshElement * tr1,
728                         const SMDS_MeshElement * tr2 )
729 {
730   if( tr1->NbNodes() != tr2->NbNodes() )
731     return false;
732   // find the 4-th node to insert into tr1
733   const SMDS_MeshNode* n4 = 0;
734   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
735   int i=0;
736   while ( !n4 && i<3 ) {
737     const SMDS_MeshNode * n = cast2Node( it->next() );
738     i++;
739     bool isDiag = ( n == theNode1 || n == theNode2 );
740     if ( !isDiag )
741       n4 = n;
742   }
743   // Make an array of nodes to be in a quadrangle
744   int iNode = 0, iFirstDiag = -1;
745   it = tr1->nodesIterator();
746   i=0;
747   while ( i<3 ) {
748     const SMDS_MeshNode * n = cast2Node( it->next() );
749     i++;
750     bool isDiag = ( n == theNode1 || n == theNode2 );
751     if ( isDiag ) {
752       if ( iFirstDiag < 0 )
753         iFirstDiag = iNode;
754       else if ( iNode - iFirstDiag == 1 )
755         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
756     }
757     else if ( n == n4 ) {
758       return false; // tr1 and tr2 should not have all the same nodes
759     }
760     theQuadNodes[ iNode++ ] = n;
761   }
762   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
763     theQuadNodes[ iNode ] = n4;
764
765   return true;
766 }
767
768 //=======================================================================
769 //function : DeleteDiag
770 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
771 //           with a quadrangle built on the same 4 nodes.
772 //           Return false if proper faces not found
773 //=======================================================================
774
775 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
776                                    const SMDS_MeshNode * theNode2)
777 {
778   myLastCreatedElems.Clear();
779   myLastCreatedNodes.Clear();
780
781   MESSAGE( "::DeleteDiag()" );
782
783   const SMDS_MeshElement *tr1, *tr2;
784   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
785     return false;
786
787   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
788   if (!F1) return false;
789   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
790   if (!F2) return false;
791   SMESHDS_Mesh * aMesh = GetMeshDS();
792
793   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
794       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
795
796     const SMDS_MeshNode* aNodes [ 4 ];
797     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
798       return false;
799
800     const SMDS_MeshElement* newElem = 0;
801     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
802     myLastCreatedElems.Append(newElem);
803     AddToSameGroups( newElem, tr1, aMesh );
804     int aShapeId = tr1->getshapeId();
805     if ( aShapeId )
806       {
807         aMesh->SetMeshElementOnShape( newElem, aShapeId );
808       }
809     aMesh->RemoveElement( tr1 );
810     aMesh->RemoveElement( tr2 );
811
812     return true;
813   }
814
815   // check case of quadratic faces
816   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
817     return false;
818   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
819     return false;
820
821   //       5
822   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
823   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
824   //    |   / |
825   //  7 +  +  + 6
826   //    | /9  |
827   //    |/    |
828   //  4 +--+--+ 3
829   //       8
830
831   const SMDS_MeshNode* N1 [6];
832   const SMDS_MeshNode* N2 [6];
833   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
834     return false;
835   // now we receive following N1 and N2 (using numeration as above image)
836   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
837   // i.e. first nodes from both arrays determ new diagonal
838
839   const SMDS_MeshNode* aNodes[8];
840   aNodes[0] = N1[0];
841   aNodes[1] = N1[1];
842   aNodes[2] = N2[0];
843   aNodes[3] = N2[1];
844   aNodes[4] = N1[3];
845   aNodes[5] = N2[5];
846   aNodes[6] = N2[3];
847   aNodes[7] = N1[5];
848
849   const SMDS_MeshElement* newElem = 0;
850   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
851                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
852   myLastCreatedElems.Append(newElem);
853   AddToSameGroups( newElem, tr1, aMesh );
854   int aShapeId = tr1->getshapeId();
855   if ( aShapeId )
856     {
857       aMesh->SetMeshElementOnShape( newElem, aShapeId );
858     }
859   aMesh->RemoveElement( tr1 );
860   aMesh->RemoveElement( tr2 );
861
862   // remove middle node (9)
863   GetMeshDS()->RemoveNode( N1[4] );
864
865   return true;
866 }
867
868 //=======================================================================
869 //function : Reorient
870 //purpose  : Reverse theElement orientation
871 //=======================================================================
872
873 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
874 {
875   MESSAGE("Reorient");
876   myLastCreatedElems.Clear();
877   myLastCreatedNodes.Clear();
878
879   if (!theElem)
880     return false;
881   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
882   if ( !it || !it->more() )
883     return false;
884
885   switch ( theElem->GetType() ) {
886
887   case SMDSAbs_Edge:
888   case SMDSAbs_Face: {
889     if(!theElem->IsQuadratic()) {
890       int i = theElem->NbNodes();
891       vector<const SMDS_MeshNode*> aNodes( i );
892       while ( it->more() )
893         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
894       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
895     }
896     else {
897       // quadratic elements
898       if(theElem->GetType()==SMDSAbs_Edge) {
899         vector<const SMDS_MeshNode*> aNodes(3);
900         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
901         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
902         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
903         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
904       }
905       else {
906         int nbn = theElem->NbNodes();
907         vector<const SMDS_MeshNode*> aNodes(nbn);
908         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
909         int i=1;
910         for(; i<nbn/2; i++) {
911           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
912         }
913         for(i=0; i<nbn/2; i++) {
914           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
915         }
916         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
917       }
918     }
919   }
920   case SMDSAbs_Volume: {
921     if (theElem->IsPoly()) {
922       // TODO reorient vtk polyhedron
923       MESSAGE("reorient vtk polyhedron ?");
924       const SMDS_VtkVolume* aPolyedre =
925         dynamic_cast<const SMDS_VtkVolume*>( theElem );
926       if (!aPolyedre) {
927         MESSAGE("Warning: bad volumic element");
928         return false;
929       }
930
931       int nbFaces = aPolyedre->NbFaces();
932       vector<const SMDS_MeshNode *> poly_nodes;
933       vector<int> quantities (nbFaces);
934
935       // reverse each face of the polyedre
936       for (int iface = 1; iface <= nbFaces; iface++) {
937         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
938         quantities[iface - 1] = nbFaceNodes;
939
940         for (inode = nbFaceNodes; inode >= 1; inode--) {
941           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
942           poly_nodes.push_back(curNode);
943         }
944       }
945
946       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
947
948     }
949     else {
950       SMDS_VolumeTool vTool;
951       if ( !vTool.Set( theElem ))
952         return false;
953       vTool.Inverse();
954       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
955       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
956     }
957   }
958   default:;
959   }
960
961   return false;
962 }
963
964 //=======================================================================
965 //function : getBadRate
966 //purpose  :
967 //=======================================================================
968
969 static double getBadRate (const SMDS_MeshElement*               theElem,
970                           SMESH::Controls::NumericalFunctorPtr& theCrit)
971 {
972   SMESH::Controls::TSequenceOfXYZ P;
973   if ( !theElem || !theCrit->GetPoints( theElem, P ))
974     return 1e100;
975   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
976   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
977 }
978
979 //=======================================================================
980 //function : QuadToTri
981 //purpose  : Cut quadrangles into triangles.
982 //           theCrit is used to select a diagonal to cut
983 //=======================================================================
984
985 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
986                                   SMESH::Controls::NumericalFunctorPtr theCrit)
987 {
988   myLastCreatedElems.Clear();
989   myLastCreatedNodes.Clear();
990
991   MESSAGE( "::QuadToTri()" );
992
993   if ( !theCrit.get() )
994     return false;
995
996   SMESHDS_Mesh * aMesh = GetMeshDS();
997
998   Handle(Geom_Surface) surface;
999   SMESH_MesherHelper   helper( *GetMesh() );
1000
1001   TIDSortedElemSet::iterator itElem;
1002   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1003     const SMDS_MeshElement* elem = *itElem;
1004     if ( !elem || elem->GetType() != SMDSAbs_Face )
1005       continue;
1006     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1007       continue;
1008
1009     // retrieve element nodes
1010     const SMDS_MeshNode* aNodes [8];
1011     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1012     int i = 0;
1013     while ( itN->more() )
1014       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1015
1016     // compare two sets of possible triangles
1017     double aBadRate1, aBadRate2; // to what extent a set is bad
1018     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1019     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1020     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1021
1022     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1023     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1024     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1025
1026     int aShapeId = FindShape( elem );
1027     const SMDS_MeshElement* newElem1 = 0;
1028     const SMDS_MeshElement* newElem2 = 0;
1029
1030     if( !elem->IsQuadratic() ) {
1031
1032       // split liner quadrangle
1033       if ( aBadRate1 <= aBadRate2 ) {
1034         // tr1 + tr2 is better
1035         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1036         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1037       }
1038       else {
1039         // tr3 + tr4 is better
1040         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1041         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1042       }
1043     }
1044     else {
1045
1046       // split quadratic quadrangle
1047
1048       // get surface elem is on
1049       if ( aShapeId != helper.GetSubShapeID() ) {
1050         surface.Nullify();
1051         TopoDS_Shape shape;
1052         if ( aShapeId > 0 )
1053           shape = aMesh->IndexToShape( aShapeId );
1054         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1055           TopoDS_Face face = TopoDS::Face( shape );
1056           surface = BRep_Tool::Surface( face );
1057           if ( !surface.IsNull() )
1058             helper.SetSubShape( shape );
1059         }
1060       }
1061       // get elem nodes
1062       const SMDS_MeshNode* aNodes [8];
1063       const SMDS_MeshNode* inFaceNode = 0;
1064       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1065       int i = 0;
1066       while ( itN->more() ) {
1067         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1068         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1069              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1070         {
1071           inFaceNode = aNodes[ i-1 ];
1072         }
1073       }
1074       // find middle point for (0,1,2,3)
1075       // and create a node in this point;
1076       gp_XYZ p( 0,0,0 );
1077       if ( surface.IsNull() ) {
1078         for(i=0; i<4; i++)
1079           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1080         p /= 4;
1081       }
1082       else {
1083         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1084         gp_XY uv( 0,0 );
1085         for(i=0; i<4; i++)
1086           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1087         uv /= 4.;
1088         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1089       }
1090       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1091       myLastCreatedNodes.Append(newN);
1092
1093       // create a new element
1094       const SMDS_MeshNode* N[6];
1095       if ( aBadRate1 <= aBadRate2 ) {
1096         N[0] = aNodes[0];
1097         N[1] = aNodes[1];
1098         N[2] = aNodes[2];
1099         N[3] = aNodes[4];
1100         N[4] = aNodes[5];
1101         N[5] = newN;
1102         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1103                                   aNodes[6], aNodes[7], newN );
1104         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1105                                   newN,      aNodes[4], aNodes[5] );
1106       }
1107       else {
1108         N[0] = aNodes[1];
1109         N[1] = aNodes[2];
1110         N[2] = aNodes[3];
1111         N[3] = aNodes[5];
1112         N[4] = aNodes[6];
1113         N[5] = newN;
1114         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1115                                   aNodes[7], aNodes[4], newN );
1116         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1117                                   newN,      aNodes[5], aNodes[6] );
1118       }
1119     } // quadratic case
1120
1121     // care of a new element
1122
1123     myLastCreatedElems.Append(newElem1);
1124     myLastCreatedElems.Append(newElem2);
1125     AddToSameGroups( newElem1, elem, aMesh );
1126     AddToSameGroups( newElem2, elem, aMesh );
1127
1128     // put a new triangle on the same shape
1129     if ( aShapeId )
1130       {
1131         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1132         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1133       }
1134     aMesh->RemoveElement( elem );
1135   }
1136   return true;
1137 }
1138
1139 //=======================================================================
1140 //function : BestSplit
1141 //purpose  : Find better diagonal for cutting.
1142 //=======================================================================
1143
1144 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1145                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1146 {
1147   myLastCreatedElems.Clear();
1148   myLastCreatedNodes.Clear();
1149
1150   if (!theCrit.get())
1151     return -1;
1152
1153   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1154     return -1;
1155
1156   if( theQuad->NbNodes()==4 ||
1157       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1158
1159     // retrieve element nodes
1160     const SMDS_MeshNode* aNodes [4];
1161     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1162     int i = 0;
1163     //while (itN->more())
1164     while (i<4) {
1165       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1166     }
1167     // compare two sets of possible triangles
1168     double aBadRate1, aBadRate2; // to what extent a set is bad
1169     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1170     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1171     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1172
1173     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1174     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1175     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1176
1177     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1178       return 1; // diagonal 1-3
1179
1180     return 2; // diagonal 2-4
1181   }
1182   return -1;
1183 }
1184
1185 namespace
1186 {
1187   // Methods of splitting volumes into tetra
1188
1189   const int theHexTo5_1[5*4+1] =
1190     {
1191       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1192     };
1193   const int theHexTo5_2[5*4+1] =
1194     {
1195       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1196     };
1197   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1198
1199   const int theHexTo6_1[6*4+1] =
1200     {
1201       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
1202     };
1203   const int theHexTo6_2[6*4+1] =
1204     {
1205       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
1206     };
1207   const int theHexTo6_3[6*4+1] =
1208     {
1209       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
1210     };
1211   const int theHexTo6_4[6*4+1] =
1212     {
1213       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
1214     };
1215   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1216
1217   const int thePyraTo2_1[2*4+1] =
1218     {
1219       0, 1, 2, 4,    0, 2, 3, 4,   -1
1220     };
1221   const int thePyraTo2_2[2*4+1] =
1222     {
1223       1, 2, 3, 4,    1, 3, 0, 4,   -1
1224     };
1225   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1226
1227   const int thePentaTo3_1[3*4+1] =
1228     {
1229       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1230     };
1231   const int thePentaTo3_2[3*4+1] =
1232     {
1233       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1234     };
1235   const int thePentaTo3_3[3*4+1] =
1236     {
1237       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1238     };
1239   const int thePentaTo3_4[3*4+1] =
1240     {
1241       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1242     };
1243   const int thePentaTo3_5[3*4+1] =
1244     {
1245       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1246     };
1247   const int thePentaTo3_6[3*4+1] =
1248     {
1249       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1250     };
1251   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1252                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1253
1254   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1255   {
1256     int _n1, _n2, _n3;
1257     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1258     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1259     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1260   };
1261   struct TSplitMethod
1262   {
1263     int        _nbTetra;
1264     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1265     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1266     bool       _ownConn;      //!< to delete _connectivity in destructor
1267     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1268
1269     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1270       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1271     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1272     bool hasFacet( const TTriangleFacet& facet ) const
1273     {
1274       const int* tetConn = _connectivity;
1275       for ( ; tetConn[0] >= 0; tetConn += 4 )
1276         if (( facet.contains( tetConn[0] ) +
1277               facet.contains( tetConn[1] ) +
1278               facet.contains( tetConn[2] ) +
1279               facet.contains( tetConn[3] )) == 3 )
1280           return true;
1281       return false;
1282     }
1283   };
1284
1285   //=======================================================================
1286   /*!
1287    * \brief return TSplitMethod for the given element
1288    */
1289   //=======================================================================
1290
1291   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1292   {
1293     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1294
1295     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1296     // an edge and a face barycenter; tertaherdons are based on triangles and
1297     // a volume barycenter
1298     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1299
1300     // Find out how adjacent volumes are split
1301
1302     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1303     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1304     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1305     {
1306       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1307       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1308       if ( nbNodes < 4 ) continue;
1309
1310       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1311       const int* nInd = vol.GetFaceNodesIndices( iF );
1312       if ( nbNodes == 4 )
1313       {
1314         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1315         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1316         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1317         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1318       }
1319       else
1320       {
1321         int iCom = 0; // common node of triangle faces to split into
1322         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1323         {
1324           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1325                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1326                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1327           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1328                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1329                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1330           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1331           {
1332             triaSplits.push_back( t012 );
1333             triaSplits.push_back( t023 );
1334             break;
1335           }
1336         }
1337       }
1338       if ( !triaSplits.empty() )
1339         hasAdjacentSplits = true;
1340     }
1341
1342     // Among variants of split method select one compliant with adjacent volumes
1343
1344     TSplitMethod method;
1345     if ( !vol.Element()->IsPoly() && !is24TetMode )
1346     {
1347       int nbVariants = 2, nbTet = 0;
1348       const int** connVariants = 0;
1349       switch ( vol.Element()->GetEntityType() )
1350       {
1351       case SMDSEntity_Hexa:
1352       case SMDSEntity_Quad_Hexa:
1353         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1354           connVariants = theHexTo5, nbTet = 5;
1355         else
1356           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1357         break;
1358       case SMDSEntity_Pyramid:
1359       case SMDSEntity_Quad_Pyramid:
1360         connVariants = thePyraTo2;  nbTet = 2;
1361         break;
1362       case SMDSEntity_Penta:
1363       case SMDSEntity_Quad_Penta:
1364         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1365         break;
1366       default:
1367         nbVariants = 0;
1368       }
1369       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1370       {
1371         // check method compliancy with adjacent tetras,
1372         // all found splits must be among facets of tetras described by this method
1373         method = TSplitMethod( nbTet, connVariants[variant] );
1374         if ( hasAdjacentSplits && method._nbTetra > 0 )
1375         {
1376           bool facetCreated = true;
1377           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1378           {
1379             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1380             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1381               facetCreated = method.hasFacet( *facet );
1382           }
1383           if ( !facetCreated )
1384             method = TSplitMethod(0); // incompatible method
1385         }
1386       }
1387     }
1388     if ( method._nbTetra < 1 )
1389     {
1390       // No standard method is applicable, use a generic solution:
1391       // each facet of a volume is split into triangles and
1392       // each of triangles and a volume barycenter form a tetrahedron.
1393
1394       int* connectivity = new int[ maxTetConnSize + 1 ];
1395       method._connectivity = connectivity;
1396       method._ownConn = true;
1397       method._baryNode = true;
1398
1399       int connSize = 0;
1400       int baryCenInd = vol.NbNodes();
1401       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1402       {
1403         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1404         const int*   nInd = vol.GetFaceNodesIndices( iF );
1405         // find common node of triangle facets of tetra to create
1406         int iCommon = 0; // index in linear numeration
1407         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1408         if ( !triaSplits.empty() )
1409         {
1410           // by found facets
1411           const TTriangleFacet* facet = &triaSplits.front();
1412           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1413             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1414                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1415               break;
1416         }
1417         else if ( nbNodes > 3 && !is24TetMode )
1418         {
1419           // find the best method of splitting into triangles by aspect ratio
1420           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1421           map< double, int > badness2iCommon;
1422           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1423           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1424           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1425             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1426             {
1427               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1428                                       nodes[ iQ*((iLast-1)%nbNodes)],
1429                                       nodes[ iQ*((iLast  )%nbNodes)]);
1430               double badness = getBadRate( &tria, aspectRatio );
1431               badness2iCommon.insert( make_pair( badness, iCommon ));
1432             }
1433           // use iCommon with lowest badness
1434           iCommon = badness2iCommon.begin()->second;
1435         }
1436         if ( iCommon >= nbNodes )
1437           iCommon = 0; // something wrong
1438
1439         // fill connectivity of tetrahedra based on a current face
1440         int nbTet = nbNodes - 2;
1441         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1442         {
1443           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1444           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1445           nbTet = nbNodes;
1446           for ( int i = 0; i < nbTet; ++i )
1447           {
1448             int i1 = i, i2 = (i+1) % nbNodes;
1449             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1450             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1451             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1452             connectivity[ connSize++ ] = faceBaryCenInd;
1453             connectivity[ connSize++ ] = baryCenInd;
1454           }
1455         }
1456         else
1457         {
1458           for ( int i = 0; i < nbTet; ++i )
1459           {
1460             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1461             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1462             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1463             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1464             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1465             connectivity[ connSize++ ] = baryCenInd;
1466           }
1467         }
1468         method._nbTetra += nbTet;
1469       }
1470       connectivity[ connSize++ ] = -1;
1471     }
1472     return method;
1473   }
1474   //================================================================================
1475   /*!
1476    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1477    */
1478   //================================================================================
1479
1480   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1481   {
1482     // find the tetrahedron including the three nodes of facet
1483     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1484     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1485     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1486     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1487     while ( volIt1->more() )
1488     {
1489       const SMDS_MeshElement* v = volIt1->next();
1490       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1491         continue;
1492       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1493       while ( volIt2->more() )
1494         if ( v != volIt2->next() )
1495           continue;
1496       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1497       while ( volIt3->more() )
1498         if ( v == volIt3->next() )
1499           return true;
1500     }
1501     return false;
1502   }
1503
1504   //=======================================================================
1505   /*!
1506    * \brief A key of a face of volume
1507    */
1508   //=======================================================================
1509
1510   struct TVolumeFaceKey: pair< int, pair< int, int> >
1511   {
1512     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1513     {
1514       TIDSortedNodeSet sortedNodes;
1515       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1516       int nbNodes = vol.NbFaceNodes( iF );
1517       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1518       for ( int i = 0; i < nbNodes; i += iQ )
1519         sortedNodes.insert( fNodes[i] );
1520       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1521       first = (*(n++))->GetID();
1522       second.first = (*(n++))->GetID();
1523       second.second = (*(n++))->GetID();
1524     }
1525   };
1526 } // namespace
1527
1528 //=======================================================================
1529 //function : SplitVolumesIntoTetra
1530 //purpose  : Split volumic elements into tetrahedra.
1531 //=======================================================================
1532
1533 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1534                                               const int                theMethodFlags)
1535 {
1536   // std-like iterator on coordinates of nodes of mesh element
1537   typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1538   NXyzIterator xyzEnd;
1539
1540   SMDS_VolumeTool    volTool;
1541   SMESH_MesherHelper helper( *GetMesh());
1542
1543   SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1544   SMESHDS_SubMesh* fSubMesh = subMesh;
1545   
1546   SMESH_SequenceOfElemPtr newNodes, newElems;
1547
1548   // map face of volume to it's baricenrtic node
1549   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1550   double bc[3];
1551
1552   TIDSortedElemSet::const_iterator elem = theElems.begin();
1553   for ( ; elem != theElems.end(); ++elem )
1554   {
1555     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1556     if ( geomType <= SMDSEntity_Quad_Tetra )
1557       continue; // tetra or face or ...
1558
1559     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1560
1561     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1562     if ( splitMethod._nbTetra < 1 ) continue;
1563
1564     // find submesh to add new tetras to
1565     if ( !subMesh || !subMesh->Contains( *elem ))
1566     {
1567       int shapeID = FindShape( *elem );
1568       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1569       subMesh = GetMeshDS()->MeshElements( shapeID );
1570     }
1571     int iQ;
1572     if ( (*elem)->IsQuadratic() )
1573     {
1574       iQ = 2;
1575       // add quadratic links to the helper
1576       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1577       {
1578         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1579         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1580           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1581       }
1582       helper.SetIsQuadratic( true );
1583     }
1584     else
1585     {
1586       iQ = 1;
1587       helper.SetIsQuadratic( false );
1588     }
1589     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1590     if ( splitMethod._baryNode )
1591     {
1592       // make a node at barycenter
1593       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1594       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1595       nodes.push_back( gcNode );
1596       newNodes.Append( gcNode );
1597     }
1598     if ( !splitMethod._faceBaryNode.empty() )
1599     {
1600       // make or find baricentric nodes of faces
1601       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1602       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1603       {
1604         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1605           volFace2BaryNode.insert
1606           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1607         if ( !f_n->second )
1608         {
1609           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1610           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1611         }
1612         nodes.push_back( iF_n->second = f_n->second );
1613       }
1614     }
1615
1616     // make tetras
1617     helper.SetElementsOnShape( true );
1618     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1619     const int* tetConn = splitMethod._connectivity;
1620     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1621       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1622                                                        nodes[ tetConn[1] ],
1623                                                        nodes[ tetConn[2] ],
1624                                                        nodes[ tetConn[3] ]));
1625
1626     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1627
1628     // Split faces on sides of the split volume
1629
1630     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1631     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1632     {
1633       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1634       if ( nbNodes < 4 ) continue;
1635
1636       // find an existing face
1637       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1638                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1639       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1640       {
1641         // make triangles
1642         helper.SetElementsOnShape( false );
1643         vector< const SMDS_MeshElement* > triangles;
1644
1645         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1646         if ( iF_n != splitMethod._faceBaryNode.end() )
1647         {
1648           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1649           {
1650             const SMDS_MeshNode* n1 = fNodes[iN];
1651             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1652             const SMDS_MeshNode *n3 = iF_n->second;
1653             if ( !volTool.IsFaceExternal( iF ))
1654               swap( n2, n3 );
1655             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1656           }
1657         }
1658         else
1659         {
1660           // among possible triangles create ones discribed by split method
1661           const int* nInd = volTool.GetFaceNodesIndices( iF );
1662           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1663           int iCom = 0; // common node of triangle faces to split into
1664           list< TTriangleFacet > facets;
1665           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1666           {
1667             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1668                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1669                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1670             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1671                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1672                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1673             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1674             {
1675               facets.push_back( t012 );
1676               facets.push_back( t023 );
1677               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1678                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1679                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1680                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1681               break;
1682             }
1683           }
1684           list< TTriangleFacet >::iterator facet = facets.begin();
1685           for ( ; facet != facets.end(); ++facet )
1686           {
1687             if ( !volTool.IsFaceExternal( iF ))
1688               swap( facet->_n2, facet->_n3 );
1689             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1690                                                  volNodes[ facet->_n2 ],
1691                                                  volNodes[ facet->_n3 ]));
1692           }
1693         }
1694         // find submesh to add new triangles in
1695         if ( !fSubMesh || !fSubMesh->Contains( face ))
1696         {
1697           int shapeID = FindShape( face );
1698           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1699         }
1700         for ( int i = 0; i < triangles.size(); ++i )
1701         {
1702           if ( !triangles.back() ) continue;
1703           if ( fSubMesh )
1704             fSubMesh->AddElement( triangles.back());
1705           newElems.Append( triangles.back() );
1706         }
1707         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1708         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1709       }
1710
1711     } // loop on volume faces to split them into triangles
1712
1713     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1714
1715   } // loop on volumes to split
1716
1717   myLastCreatedNodes = newNodes;
1718   myLastCreatedElems = newElems;
1719 }
1720
1721 //=======================================================================
1722 //function : AddToSameGroups
1723 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1724 //=======================================================================
1725
1726 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1727                                         const SMDS_MeshElement* elemInGroups,
1728                                         SMESHDS_Mesh *          aMesh)
1729 {
1730   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1731   if (!groups.empty()) {
1732     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1733     for ( ; grIt != groups.end(); grIt++ ) {
1734       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1735       if ( group && group->Contains( elemInGroups ))
1736         group->SMDSGroup().Add( elemToAdd );
1737     }
1738   }
1739 }
1740
1741
1742 //=======================================================================
1743 //function : RemoveElemFromGroups
1744 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1745 //=======================================================================
1746 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1747                                              SMESHDS_Mesh *          aMesh)
1748 {
1749   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1750   if (!groups.empty())
1751   {
1752     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1753     for (; GrIt != groups.end(); GrIt++)
1754     {
1755       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1756       if (!grp || grp->IsEmpty()) continue;
1757       grp->SMDSGroup().Remove(removeelem);
1758     }
1759   }
1760 }
1761
1762 //================================================================================
1763 /*!
1764  * \brief Replace elemToRm by elemToAdd in the all groups
1765  */
1766 //================================================================================
1767
1768 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1769                                             const SMDS_MeshElement* elemToAdd,
1770                                             SMESHDS_Mesh *          aMesh)
1771 {
1772   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1773   if (!groups.empty()) {
1774     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1775     for ( ; grIt != groups.end(); grIt++ ) {
1776       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1777       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1778         group->SMDSGroup().Add( elemToAdd );
1779     }
1780   }
1781 }
1782
1783 //================================================================================
1784 /*!
1785  * \brief Replace elemToRm by elemToAdd in the all groups
1786  */
1787 //================================================================================
1788
1789 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1790                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1791                                             SMESHDS_Mesh *                         aMesh)
1792 {
1793   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1794   if (!groups.empty())
1795   {
1796     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1797     for ( ; grIt != groups.end(); grIt++ ) {
1798       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1799       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1800         for ( int i = 0; i < elemToAdd.size(); ++i )
1801           group->SMDSGroup().Add( elemToAdd[ i ] );
1802     }
1803   }
1804 }
1805
1806 //=======================================================================
1807 //function : QuadToTri
1808 //purpose  : Cut quadrangles into triangles.
1809 //           theCrit is used to select a diagonal to cut
1810 //=======================================================================
1811
1812 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1813                                   const bool         the13Diag)
1814 {
1815   myLastCreatedElems.Clear();
1816   myLastCreatedNodes.Clear();
1817
1818   MESSAGE( "::QuadToTri()" );
1819
1820   SMESHDS_Mesh * aMesh = GetMeshDS();
1821
1822   Handle(Geom_Surface) surface;
1823   SMESH_MesherHelper   helper( *GetMesh() );
1824
1825   TIDSortedElemSet::iterator itElem;
1826   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1827     const SMDS_MeshElement* elem = *itElem;
1828     if ( !elem || elem->GetType() != SMDSAbs_Face )
1829       continue;
1830     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1831     if(!isquad) continue;
1832
1833     if(elem->NbNodes()==4) {
1834       // retrieve element nodes
1835       const SMDS_MeshNode* aNodes [4];
1836       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1837       int i = 0;
1838       while ( itN->more() )
1839         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1840
1841       int aShapeId = FindShape( elem );
1842       const SMDS_MeshElement* newElem1 = 0;
1843       const SMDS_MeshElement* newElem2 = 0;
1844       if ( the13Diag ) {
1845         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1846         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1847       }
1848       else {
1849         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1850         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1851       }
1852       myLastCreatedElems.Append(newElem1);
1853       myLastCreatedElems.Append(newElem2);
1854       // put a new triangle on the same shape and add to the same groups
1855       if ( aShapeId )
1856         {
1857           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1858           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1859         }
1860       AddToSameGroups( newElem1, elem, aMesh );
1861       AddToSameGroups( newElem2, elem, aMesh );
1862       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1863       aMesh->RemoveElement( elem );
1864     }
1865
1866     // Quadratic quadrangle
1867
1868     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1869
1870       // get surface elem is on
1871       int aShapeId = FindShape( elem );
1872       if ( aShapeId != helper.GetSubShapeID() ) {
1873         surface.Nullify();
1874         TopoDS_Shape shape;
1875         if ( aShapeId > 0 )
1876           shape = aMesh->IndexToShape( aShapeId );
1877         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1878           TopoDS_Face face = TopoDS::Face( shape );
1879           surface = BRep_Tool::Surface( face );
1880           if ( !surface.IsNull() )
1881             helper.SetSubShape( shape );
1882         }
1883       }
1884
1885       const SMDS_MeshNode* aNodes [8];
1886       const SMDS_MeshNode* inFaceNode = 0;
1887       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1888       int i = 0;
1889       while ( itN->more() ) {
1890         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1891         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1892              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1893         {
1894           inFaceNode = aNodes[ i-1 ];
1895         }
1896       }
1897
1898       // find middle point for (0,1,2,3)
1899       // and create a node in this point;
1900       gp_XYZ p( 0,0,0 );
1901       if ( surface.IsNull() ) {
1902         for(i=0; i<4; i++)
1903           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1904         p /= 4;
1905       }
1906       else {
1907         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1908         gp_XY uv( 0,0 );
1909         for(i=0; i<4; i++)
1910           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1911         uv /= 4.;
1912         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1913       }
1914       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1915       myLastCreatedNodes.Append(newN);
1916
1917       // create a new element
1918       const SMDS_MeshElement* newElem1 = 0;
1919       const SMDS_MeshElement* newElem2 = 0;
1920       const SMDS_MeshNode* N[6];
1921       if ( the13Diag ) {
1922         N[0] = aNodes[0];
1923         N[1] = aNodes[1];
1924         N[2] = aNodes[2];
1925         N[3] = aNodes[4];
1926         N[4] = aNodes[5];
1927         N[5] = newN;
1928         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1929                                   aNodes[6], aNodes[7], newN );
1930         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1931                                   newN,      aNodes[4], aNodes[5] );
1932       }
1933       else {
1934         N[0] = aNodes[1];
1935         N[1] = aNodes[2];
1936         N[2] = aNodes[3];
1937         N[3] = aNodes[5];
1938         N[4] = aNodes[6];
1939         N[5] = newN;
1940         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1941                                   aNodes[7], aNodes[4], newN );
1942         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1943                                   newN,      aNodes[5], aNodes[6] );
1944       }
1945       myLastCreatedElems.Append(newElem1);
1946       myLastCreatedElems.Append(newElem2);
1947       // put a new triangle on the same shape and add to the same groups
1948       if ( aShapeId )
1949         {
1950           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1951           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1952         }
1953       AddToSameGroups( newElem1, elem, aMesh );
1954       AddToSameGroups( newElem2, elem, aMesh );
1955       aMesh->RemoveElement( elem );
1956     }
1957   }
1958
1959   return true;
1960 }
1961
1962 //=======================================================================
1963 //function : getAngle
1964 //purpose  :
1965 //=======================================================================
1966
1967 double getAngle(const SMDS_MeshElement * tr1,
1968                 const SMDS_MeshElement * tr2,
1969                 const SMDS_MeshNode *    n1,
1970                 const SMDS_MeshNode *    n2)
1971 {
1972   double angle = 2*PI; // bad angle
1973
1974   // get normals
1975   SMESH::Controls::TSequenceOfXYZ P1, P2;
1976   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1977        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1978     return angle;
1979   gp_Vec N1,N2;
1980   if(!tr1->IsQuadratic())
1981     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1982   else
1983     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1984   if ( N1.SquareMagnitude() <= gp::Resolution() )
1985     return angle;
1986   if(!tr2->IsQuadratic())
1987     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1988   else
1989     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1990   if ( N2.SquareMagnitude() <= gp::Resolution() )
1991     return angle;
1992
1993   // find the first diagonal node n1 in the triangles:
1994   // take in account a diagonal link orientation
1995   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1996   for ( int t = 0; t < 2; t++ ) {
1997     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1998     int i = 0, iDiag = -1;
1999     while ( it->more()) {
2000       const SMDS_MeshElement *n = it->next();
2001       if ( n == n1 || n == n2 )
2002         if ( iDiag < 0)
2003           iDiag = i;
2004         else {
2005           if ( i - iDiag == 1 )
2006             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2007           else
2008             nFirst[ t ] = n;
2009           break;
2010         }
2011       i++;
2012     }
2013   }
2014   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2015     N2.Reverse();
2016
2017   angle = N1.Angle( N2 );
2018   //SCRUTE( angle );
2019   return angle;
2020 }
2021
2022 // =================================================
2023 // class generating a unique ID for a pair of nodes
2024 // and able to return nodes by that ID
2025 // =================================================
2026 class LinkID_Gen {
2027 public:
2028
2029   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2030     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2031   {}
2032
2033   long GetLinkID (const SMDS_MeshNode * n1,
2034                   const SMDS_MeshNode * n2) const
2035   {
2036     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2037   }
2038
2039   bool GetNodes (const long             theLinkID,
2040                  const SMDS_MeshNode* & theNode1,
2041                  const SMDS_MeshNode* & theNode2) const
2042   {
2043     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2044     if ( !theNode1 ) return false;
2045     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2046     if ( !theNode2 ) return false;
2047     return true;
2048   }
2049
2050 private:
2051   LinkID_Gen();
2052   const SMESHDS_Mesh* myMesh;
2053   long                myMaxID;
2054 };
2055
2056
2057 //=======================================================================
2058 //function : TriToQuad
2059 //purpose  : Fuse neighbour triangles into quadrangles.
2060 //           theCrit is used to select a neighbour to fuse with.
2061 //           theMaxAngle is a max angle between element normals at which
2062 //           fusion is still performed.
2063 //=======================================================================
2064
2065 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2066                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2067                                   const double                         theMaxAngle)
2068 {
2069   myLastCreatedElems.Clear();
2070   myLastCreatedNodes.Clear();
2071
2072   MESSAGE( "::TriToQuad()" );
2073
2074   if ( !theCrit.get() )
2075     return false;
2076
2077   SMESHDS_Mesh * aMesh = GetMeshDS();
2078
2079   // Prepare data for algo: build
2080   // 1. map of elements with their linkIDs
2081   // 2. map of linkIDs with their elements
2082
2083   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2084   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2085   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2086   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2087
2088   TIDSortedElemSet::iterator itElem;
2089   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2090     const SMDS_MeshElement* elem = *itElem;
2091     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2092     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2093     if(!IsTria) continue;
2094
2095     // retrieve element nodes
2096     const SMDS_MeshNode* aNodes [4];
2097     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2098     int i = 0;
2099     while ( i<3 )
2100       aNodes[ i++ ] = cast2Node( itN->next() );
2101     aNodes[ 3 ] = aNodes[ 0 ];
2102
2103     // fill maps
2104     for ( i = 0; i < 3; i++ ) {
2105       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2106       // check if elements sharing a link can be fused
2107       itLE = mapLi_listEl.find( link );
2108       if ( itLE != mapLi_listEl.end() ) {
2109         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2110           continue;
2111         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2112         //if ( FindShape( elem ) != FindShape( elem2 ))
2113         //  continue; // do not fuse triangles laying on different shapes
2114         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2115           continue; // avoid making badly shaped quads
2116         (*itLE).second.push_back( elem );
2117       }
2118       else {
2119         mapLi_listEl[ link ].push_back( elem );
2120       }
2121       mapEl_setLi [ elem ].insert( link );
2122     }
2123   }
2124   // Clean the maps from the links shared by a sole element, ie
2125   // links to which only one element is bound in mapLi_listEl
2126
2127   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2128     int nbElems = (*itLE).second.size();
2129     if ( nbElems < 2  ) {
2130       const SMDS_MeshElement* elem = (*itLE).second.front();
2131       SMESH_TLink link = (*itLE).first;
2132       mapEl_setLi[ elem ].erase( link );
2133       if ( mapEl_setLi[ elem ].empty() )
2134         mapEl_setLi.erase( elem );
2135     }
2136   }
2137
2138   // Algo: fuse triangles into quadrangles
2139
2140   while ( ! mapEl_setLi.empty() ) {
2141     // Look for the start element:
2142     // the element having the least nb of shared links
2143     const SMDS_MeshElement* startElem = 0;
2144     int minNbLinks = 4;
2145     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2146       int nbLinks = (*itEL).second.size();
2147       if ( nbLinks < minNbLinks ) {
2148         startElem = (*itEL).first;
2149         minNbLinks = nbLinks;
2150         if ( minNbLinks == 1 )
2151           break;
2152       }
2153     }
2154
2155     // search elements to fuse starting from startElem or links of elements
2156     // fused earlyer - startLinks
2157     list< SMESH_TLink > startLinks;
2158     while ( startElem || !startLinks.empty() ) {
2159       while ( !startElem && !startLinks.empty() ) {
2160         // Get an element to start, by a link
2161         SMESH_TLink linkId = startLinks.front();
2162         startLinks.pop_front();
2163         itLE = mapLi_listEl.find( linkId );
2164         if ( itLE != mapLi_listEl.end() ) {
2165           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2166           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2167           for ( ; itE != listElem.end() ; itE++ )
2168             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2169               startElem = (*itE);
2170           mapLi_listEl.erase( itLE );
2171         }
2172       }
2173
2174       if ( startElem ) {
2175         // Get candidates to be fused
2176         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2177         const SMESH_TLink *link12, *link13;
2178         startElem = 0;
2179         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2180         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2181         ASSERT( !setLi.empty() );
2182         set< SMESH_TLink >::iterator itLi;
2183         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2184         {
2185           const SMESH_TLink & link = (*itLi);
2186           itLE = mapLi_listEl.find( link );
2187           if ( itLE == mapLi_listEl.end() )
2188             continue;
2189
2190           const SMDS_MeshElement* elem = (*itLE).second.front();
2191           if ( elem == tr1 )
2192             elem = (*itLE).second.back();
2193           mapLi_listEl.erase( itLE );
2194           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2195             continue;
2196           if ( tr2 ) {
2197             tr3 = elem;
2198             link13 = &link;
2199           }
2200           else {
2201             tr2 = elem;
2202             link12 = &link;
2203           }
2204
2205           // add other links of elem to list of links to re-start from
2206           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2207           set< SMESH_TLink >::iterator it;
2208           for ( it = links.begin(); it != links.end(); it++ ) {
2209             const SMESH_TLink& link2 = (*it);
2210             if ( link2 != link )
2211               startLinks.push_back( link2 );
2212           }
2213         }
2214
2215         // Get nodes of possible quadrangles
2216         const SMDS_MeshNode *n12 [4], *n13 [4];
2217         bool Ok12 = false, Ok13 = false;
2218         const SMDS_MeshNode *linkNode1, *linkNode2;
2219         if(tr2) {
2220           linkNode1 = link12->first;
2221           linkNode2 = link12->second;
2222           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2223             Ok12 = true;
2224         }
2225         if(tr3) {
2226           linkNode1 = link13->first;
2227           linkNode2 = link13->second;
2228           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2229             Ok13 = true;
2230         }
2231
2232         // Choose a pair to fuse
2233         if ( Ok12 && Ok13 ) {
2234           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2235           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2236           double aBadRate12 = getBadRate( &quad12, theCrit );
2237           double aBadRate13 = getBadRate( &quad13, theCrit );
2238           if (  aBadRate13 < aBadRate12 )
2239             Ok12 = false;
2240           else
2241             Ok13 = false;
2242         }
2243
2244         // Make quadrangles
2245         // and remove fused elems and removed links from the maps
2246         mapEl_setLi.erase( tr1 );
2247         if ( Ok12 ) {
2248           mapEl_setLi.erase( tr2 );
2249           mapLi_listEl.erase( *link12 );
2250           if(tr1->NbNodes()==3) {
2251             const SMDS_MeshElement* newElem = 0;
2252             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2253             myLastCreatedElems.Append(newElem);
2254             AddToSameGroups( newElem, tr1, aMesh );
2255             int aShapeId = tr1->getshapeId();
2256             if ( aShapeId )
2257               {
2258                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2259               }
2260             aMesh->RemoveElement( tr1 );
2261             aMesh->RemoveElement( tr2 );
2262           }
2263           else {
2264             const SMDS_MeshNode* N1 [6];
2265             const SMDS_MeshNode* N2 [6];
2266             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2267             // now we receive following N1 and N2 (using numeration as above image)
2268             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2269             // i.e. first nodes from both arrays determ new diagonal
2270             const SMDS_MeshNode* aNodes[8];
2271             aNodes[0] = N1[0];
2272             aNodes[1] = N1[1];
2273             aNodes[2] = N2[0];
2274             aNodes[3] = N2[1];
2275             aNodes[4] = N1[3];
2276             aNodes[5] = N2[5];
2277             aNodes[6] = N2[3];
2278             aNodes[7] = N1[5];
2279             const SMDS_MeshElement* newElem = 0;
2280             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2281                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2282             myLastCreatedElems.Append(newElem);
2283             AddToSameGroups( newElem, tr1, aMesh );
2284             int aShapeId = tr1->getshapeId();
2285             if ( aShapeId )
2286               {
2287                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2288               }
2289             aMesh->RemoveElement( tr1 );
2290             aMesh->RemoveElement( tr2 );
2291             // remove middle node (9)
2292             GetMeshDS()->RemoveNode( N1[4] );
2293           }
2294         }
2295         else if ( Ok13 ) {
2296           mapEl_setLi.erase( tr3 );
2297           mapLi_listEl.erase( *link13 );
2298           if(tr1->NbNodes()==3) {
2299             const SMDS_MeshElement* newElem = 0;
2300             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2301             myLastCreatedElems.Append(newElem);
2302             AddToSameGroups( newElem, tr1, aMesh );
2303             int aShapeId = tr1->getshapeId();
2304             if ( aShapeId )
2305               {
2306                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2307               }
2308             aMesh->RemoveElement( tr1 );
2309             aMesh->RemoveElement( tr3 );
2310           }
2311           else {
2312             const SMDS_MeshNode* N1 [6];
2313             const SMDS_MeshNode* N2 [6];
2314             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2315             // now we receive following N1 and N2 (using numeration as above image)
2316             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2317             // i.e. first nodes from both arrays determ new diagonal
2318             const SMDS_MeshNode* aNodes[8];
2319             aNodes[0] = N1[0];
2320             aNodes[1] = N1[1];
2321             aNodes[2] = N2[0];
2322             aNodes[3] = N2[1];
2323             aNodes[4] = N1[3];
2324             aNodes[5] = N2[5];
2325             aNodes[6] = N2[3];
2326             aNodes[7] = N1[5];
2327             const SMDS_MeshElement* newElem = 0;
2328             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2329                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2330             myLastCreatedElems.Append(newElem);
2331             AddToSameGroups( newElem, tr1, aMesh );
2332             int aShapeId = tr1->getshapeId();
2333             if ( aShapeId )
2334               {
2335                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2336               }
2337             aMesh->RemoveElement( tr1 );
2338             aMesh->RemoveElement( tr3 );
2339             // remove middle node (9)
2340             GetMeshDS()->RemoveNode( N1[4] );
2341           }
2342         }
2343
2344         // Next element to fuse: the rejected one
2345         if ( tr3 )
2346           startElem = Ok12 ? tr3 : tr2;
2347
2348       } // if ( startElem )
2349     } // while ( startElem || !startLinks.empty() )
2350   } // while ( ! mapEl_setLi.empty() )
2351
2352   return true;
2353 }
2354
2355
2356 /*#define DUMPSO(txt) \
2357 //  cout << txt << endl;
2358 //=============================================================================
2359 //
2360 //
2361 //
2362 //=============================================================================
2363 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2364 {
2365 if ( i1 == i2 )
2366 return;
2367 int tmp = idNodes[ i1 ];
2368 idNodes[ i1 ] = idNodes[ i2 ];
2369 idNodes[ i2 ] = tmp;
2370 gp_Pnt Ptmp = P[ i1 ];
2371 P[ i1 ] = P[ i2 ];
2372 P[ i2 ] = Ptmp;
2373 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2374 }
2375
2376 //=======================================================================
2377 //function : SortQuadNodes
2378 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2379 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2380 //           1 or 2 else 0.
2381 //=======================================================================
2382
2383 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2384 int               idNodes[] )
2385 {
2386   gp_Pnt P[4];
2387   int i;
2388   for ( i = 0; i < 4; i++ ) {
2389     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2390     if ( !n ) return 0;
2391     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2392   }
2393
2394   gp_Vec V1(P[0], P[1]);
2395   gp_Vec V2(P[0], P[2]);
2396   gp_Vec V3(P[0], P[3]);
2397
2398   gp_Vec Cross1 = V1 ^ V2;
2399   gp_Vec Cross2 = V2 ^ V3;
2400
2401   i = 0;
2402   if (Cross1.Dot(Cross2) < 0)
2403   {
2404     Cross1 = V2 ^ V1;
2405     Cross2 = V1 ^ V3;
2406
2407     if (Cross1.Dot(Cross2) < 0)
2408       i = 2;
2409     else
2410       i = 1;
2411     swap ( i, i + 1, idNodes, P );
2412
2413     //     for ( int ii = 0; ii < 4; ii++ ) {
2414     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2415     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2416     //     }
2417   }
2418   return i;
2419 }
2420
2421 //=======================================================================
2422 //function : SortHexaNodes
2423 //purpose  : Set 8 nodes of a hexahedron in a good order.
2424 //           Return success status
2425 //=======================================================================
2426
2427 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2428                                       int               idNodes[] )
2429 {
2430   gp_Pnt P[8];
2431   int i;
2432   DUMPSO( "INPUT: ========================================");
2433   for ( i = 0; i < 8; i++ ) {
2434     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2435     if ( !n ) return false;
2436     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2437     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2438   }
2439   DUMPSO( "========================================");
2440
2441
2442   set<int> faceNodes;  // ids of bottom face nodes, to be found
2443   set<int> checkedId1; // ids of tried 2-nd nodes
2444   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2445   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2446   int iMin, iLoop1 = 0;
2447
2448   // Loop to try the 2-nd nodes
2449
2450   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2451   {
2452     // Find not checked 2-nd node
2453     for ( i = 1; i < 8; i++ )
2454       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2455         int id1 = idNodes[i];
2456         swap ( 1, i, idNodes, P );
2457         checkedId1.insert ( id1 );
2458         break;
2459       }
2460
2461     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2462     // ie that all but meybe one (id3 which is on the same face) nodes
2463     // lay on the same side from the triangle plane.
2464
2465     bool manyInPlane = false; // more than 4 nodes lay in plane
2466     int iLoop2 = 0;
2467     while ( ++iLoop2 < 6 ) {
2468
2469       // get 1-2-3 plane coeffs
2470       Standard_Real A, B, C, D;
2471       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2472       if ( N.SquareMagnitude() > gp::Resolution() )
2473       {
2474         gp_Pln pln ( P[0], N );
2475         pln.Coefficients( A, B, C, D );
2476
2477         // find the node (iMin) closest to pln
2478         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2479         set<int> idInPln;
2480         for ( i = 3; i < 8; i++ ) {
2481           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2482           if ( fabs( dist[i] ) < minDist ) {
2483             minDist = fabs( dist[i] );
2484             iMin = i;
2485           }
2486           if ( fabs( dist[i] ) <= tol )
2487             idInPln.insert( idNodes[i] );
2488         }
2489
2490         // there should not be more than 4 nodes in bottom plane
2491         if ( idInPln.size() > 1 )
2492         {
2493           DUMPSO( "### idInPln.size() = " << idInPln.size());
2494           // idInPlane does not contain the first 3 nodes
2495           if ( manyInPlane || idInPln.size() == 5)
2496             return false; // all nodes in one plane
2497           manyInPlane = true;
2498
2499           // set the 1-st node to be not in plane
2500           for ( i = 3; i < 8; i++ ) {
2501             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2502               DUMPSO( "### Reset 0-th node");
2503               swap( 0, i, idNodes, P );
2504               break;
2505             }
2506           }
2507
2508           // reset to re-check second nodes
2509           leastDist = DBL_MAX;
2510           faceNodes.clear();
2511           checkedId1.clear();
2512           iLoop1 = 0;
2513           break; // from iLoop2;
2514         }
2515
2516         // check that the other 4 nodes are on the same side
2517         bool sameSide = true;
2518         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2519         for ( i = 3; sameSide && i < 8; i++ ) {
2520           if ( i != iMin )
2521             sameSide = ( isNeg == dist[i] <= 0.);
2522         }
2523
2524         // keep best solution
2525         if ( sameSide && minDist < leastDist ) {
2526           leastDist = minDist;
2527           faceNodes.clear();
2528           faceNodes.insert( idNodes[ 1 ] );
2529           faceNodes.insert( idNodes[ 2 ] );
2530           faceNodes.insert( idNodes[ iMin ] );
2531           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2532                   << " leastDist = " << leastDist);
2533           if ( leastDist <= DBL_MIN )
2534             break;
2535         }
2536       }
2537
2538       // set next 3-d node to check
2539       int iNext = 2 + iLoop2;
2540       if ( iNext < 8 ) {
2541         DUMPSO( "Try 2-nd");
2542         swap ( 2, iNext, idNodes, P );
2543       }
2544     } // while ( iLoop2 < 6 )
2545   } // iLoop1
2546
2547   if ( faceNodes.empty() ) return false;
2548
2549   // Put the faceNodes in proper places
2550   for ( i = 4; i < 8; i++ ) {
2551     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2552       // find a place to put
2553       int iTo = 1;
2554       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2555         iTo++;
2556       DUMPSO( "Set faceNodes");
2557       swap ( iTo, i, idNodes, P );
2558     }
2559   }
2560
2561
2562   // Set nodes of the found bottom face in good order
2563   DUMPSO( " Found bottom face: ");
2564   i = SortQuadNodes( theMesh, idNodes );
2565   if ( i ) {
2566     gp_Pnt Ptmp = P[ i ];
2567     P[ i ] = P[ i+1 ];
2568     P[ i+1 ] = Ptmp;
2569   }
2570   //   else
2571   //     for ( int ii = 0; ii < 4; ii++ ) {
2572   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2573   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2574   //    }
2575
2576   // Gravity center of the top and bottom faces
2577   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2578   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2579
2580   // Get direction from the bottom to the top face
2581   gp_Vec upDir ( aGCb, aGCt );
2582   Standard_Real upDirSize = upDir.Magnitude();
2583   if ( upDirSize <= gp::Resolution() ) return false;
2584   upDir / upDirSize;
2585
2586   // Assure that the bottom face normal points up
2587   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2588   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2589   if ( Nb.Dot( upDir ) < 0 ) {
2590     DUMPSO( "Reverse bottom face");
2591     swap( 1, 3, idNodes, P );
2592   }
2593
2594   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2595   Standard_Real minDist = DBL_MAX;
2596   for ( i = 4; i < 8; i++ ) {
2597     // projection of P[i] to the plane defined by P[0] and upDir
2598     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2599     Standard_Real sqDist = P[0].SquareDistance( Pp );
2600     if ( sqDist < minDist ) {
2601       minDist = sqDist;
2602       iMin = i;
2603     }
2604   }
2605   DUMPSO( "Set 4-th");
2606   swap ( 4, iMin, idNodes, P );
2607
2608   // Set nodes of the top face in good order
2609   DUMPSO( "Sort top face");
2610   i = SortQuadNodes( theMesh, &idNodes[4] );
2611   if ( i ) {
2612     i += 4;
2613     gp_Pnt Ptmp = P[ i ];
2614     P[ i ] = P[ i+1 ];
2615     P[ i+1 ] = Ptmp;
2616   }
2617
2618   // Assure that direction of the top face normal is from the bottom face
2619   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2620   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2621   if ( Nt.Dot( upDir ) < 0 ) {
2622     DUMPSO( "Reverse top face");
2623     swap( 5, 7, idNodes, P );
2624   }
2625
2626   //   DUMPSO( "OUTPUT: ========================================");
2627   //   for ( i = 0; i < 8; i++ ) {
2628   //     float *p = ugrid->GetPoint(idNodes[i]);
2629   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2630   //   }
2631
2632   return true;
2633 }*/
2634
2635 //================================================================================
2636 /*!
2637  * \brief Return nodes linked to the given one
2638  * \param theNode - the node
2639  * \param linkedNodes - the found nodes
2640  * \param type - the type of elements to check
2641  *
2642  * Medium nodes are ignored
2643  */
2644 //================================================================================
2645
2646 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2647                                        TIDSortedElemSet &   linkedNodes,
2648                                        SMDSAbs_ElementType  type )
2649 {
2650   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2651   while ( elemIt->more() )
2652   {
2653     const SMDS_MeshElement* elem = elemIt->next();
2654     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2655     if ( elem->GetType() == SMDSAbs_Volume )
2656     {
2657       SMDS_VolumeTool vol( elem );
2658       while ( nodeIt->more() ) {
2659         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2660         if ( theNode != n && vol.IsLinked( theNode, n ))
2661           linkedNodes.insert( n );
2662       }
2663     }
2664     else
2665     {
2666       for ( int i = 0; nodeIt->more(); ++i ) {
2667         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2668         if ( n == theNode ) {
2669           int iBefore = i - 1;
2670           int iAfter  = i + 1;
2671           if ( elem->IsQuadratic() ) {
2672             int nb = elem->NbNodes() / 2;
2673             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2674             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2675           }
2676           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2677           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2678         }
2679       }
2680     }
2681   }
2682 }
2683
2684 //=======================================================================
2685 //function : laplacianSmooth
2686 //purpose  : pulls theNode toward the center of surrounding nodes directly
2687 //           connected to that node along an element edge
2688 //=======================================================================
2689
2690 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2691                      const Handle(Geom_Surface)&          theSurface,
2692                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2693 {
2694   // find surrounding nodes
2695
2696   TIDSortedElemSet nodeSet;
2697   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2698
2699   // compute new coodrs
2700
2701   double coord[] = { 0., 0., 0. };
2702   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2703   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2704     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2705     if ( theSurface.IsNull() ) { // smooth in 3D
2706       coord[0] += node->X();
2707       coord[1] += node->Y();
2708       coord[2] += node->Z();
2709     }
2710     else { // smooth in 2D
2711       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2712       gp_XY* uv = theUVMap[ node ];
2713       coord[0] += uv->X();
2714       coord[1] += uv->Y();
2715     }
2716   }
2717   int nbNodes = nodeSet.size();
2718   if ( !nbNodes )
2719     return;
2720   coord[0] /= nbNodes;
2721   coord[1] /= nbNodes;
2722
2723   if ( !theSurface.IsNull() ) {
2724     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2725     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2726     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2727     coord[0] = p3d.X();
2728     coord[1] = p3d.Y();
2729     coord[2] = p3d.Z();
2730   }
2731   else
2732     coord[2] /= nbNodes;
2733
2734   // move node
2735
2736   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2737 }
2738
2739 //=======================================================================
2740 //function : centroidalSmooth
2741 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2742 //           surrounding elements
2743 //=======================================================================
2744
2745 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2746                       const Handle(Geom_Surface)&          theSurface,
2747                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2748 {
2749   gp_XYZ aNewXYZ(0.,0.,0.);
2750   SMESH::Controls::Area anAreaFunc;
2751   double totalArea = 0.;
2752   int nbElems = 0;
2753
2754   // compute new XYZ
2755
2756   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2757   while ( elemIt->more() )
2758   {
2759     const SMDS_MeshElement* elem = elemIt->next();
2760     nbElems++;
2761
2762     gp_XYZ elemCenter(0.,0.,0.);
2763     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2764     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2765     int nn = elem->NbNodes();
2766     if(elem->IsQuadratic()) nn = nn/2;
2767     int i=0;
2768     //while ( itN->more() ) {
2769     while ( i<nn ) {
2770       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2771       i++;
2772       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2773       aNodePoints.push_back( aP );
2774       if ( !theSurface.IsNull() ) { // smooth in 2D
2775         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2776         gp_XY* uv = theUVMap[ aNode ];
2777         aP.SetCoord( uv->X(), uv->Y(), 0. );
2778       }
2779       elemCenter += aP;
2780     }
2781     double elemArea = anAreaFunc.GetValue( aNodePoints );
2782     totalArea += elemArea;
2783     elemCenter /= nn;
2784     aNewXYZ += elemCenter * elemArea;
2785   }
2786   aNewXYZ /= totalArea;
2787   if ( !theSurface.IsNull() ) {
2788     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2789     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2790   }
2791
2792   // move node
2793
2794   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2795 }
2796
2797 //=======================================================================
2798 //function : getClosestUV
2799 //purpose  : return UV of closest projection
2800 //=======================================================================
2801
2802 static bool getClosestUV (Extrema_GenExtPS& projector,
2803                           const gp_Pnt&     point,
2804                           gp_XY &           result)
2805 {
2806   projector.Perform( point );
2807   if ( projector.IsDone() ) {
2808     double u, v, minVal = DBL_MAX;
2809     for ( int i = projector.NbExt(); i > 0; i-- )
2810       if ( projector.Value( i ) < minVal ) {
2811         minVal = projector.Value( i );
2812         projector.Point( i ).Parameter( u, v );
2813       }
2814     result.SetCoord( u, v );
2815     return true;
2816   }
2817   return false;
2818 }
2819
2820 //=======================================================================
2821 //function : Smooth
2822 //purpose  : Smooth theElements during theNbIterations or until a worst
2823 //           element has aspect ratio <= theTgtAspectRatio.
2824 //           Aspect Ratio varies in range [1.0, inf].
2825 //           If theElements is empty, the whole mesh is smoothed.
2826 //           theFixedNodes contains additionally fixed nodes. Nodes built
2827 //           on edges and boundary nodes are always fixed.
2828 //=======================================================================
2829
2830 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2831                                set<const SMDS_MeshNode*> & theFixedNodes,
2832                                const SmoothMethod          theSmoothMethod,
2833                                const int                   theNbIterations,
2834                                double                      theTgtAspectRatio,
2835                                const bool                  the2D)
2836 {
2837   myLastCreatedElems.Clear();
2838   myLastCreatedNodes.Clear();
2839
2840   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2841
2842   if ( theTgtAspectRatio < 1.0 )
2843     theTgtAspectRatio = 1.0;
2844
2845   const double disttol = 1.e-16;
2846
2847   SMESH::Controls::AspectRatio aQualityFunc;
2848
2849   SMESHDS_Mesh* aMesh = GetMeshDS();
2850
2851   if ( theElems.empty() ) {
2852     // add all faces to theElems
2853     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2854     while ( fIt->more() ) {
2855       const SMDS_MeshElement* face = fIt->next();
2856       theElems.insert( face );
2857     }
2858   }
2859   // get all face ids theElems are on
2860   set< int > faceIdSet;
2861   TIDSortedElemSet::iterator itElem;
2862   if ( the2D )
2863     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2864       int fId = FindShape( *itElem );
2865       // check that corresponding submesh exists and a shape is face
2866       if (fId &&
2867           faceIdSet.find( fId ) == faceIdSet.end() &&
2868           aMesh->MeshElements( fId )) {
2869         TopoDS_Shape F = aMesh->IndexToShape( fId );
2870         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2871           faceIdSet.insert( fId );
2872       }
2873     }
2874   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2875
2876   // ===============================================
2877   // smooth elements on each TopoDS_Face separately
2878   // ===============================================
2879
2880   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2881   for ( ; fId != faceIdSet.rend(); ++fId ) {
2882     // get face surface and submesh
2883     Handle(Geom_Surface) surface;
2884     SMESHDS_SubMesh* faceSubMesh = 0;
2885     TopoDS_Face face;
2886     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2887     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2888     bool isUPeriodic = false, isVPeriodic = false;
2889     if ( *fId ) {
2890       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2891       surface = BRep_Tool::Surface( face );
2892       faceSubMesh = aMesh->MeshElements( *fId );
2893       fToler2 = BRep_Tool::Tolerance( face );
2894       fToler2 *= fToler2 * 10.;
2895       isUPeriodic = surface->IsUPeriodic();
2896       if ( isUPeriodic )
2897         vPeriod = surface->UPeriod();
2898       isVPeriodic = surface->IsVPeriodic();
2899       if ( isVPeriodic )
2900         uPeriod = surface->VPeriod();
2901       surface->Bounds( u1, u2, v1, v2 );
2902     }
2903     // ---------------------------------------------------------
2904     // for elements on a face, find movable and fixed nodes and
2905     // compute UV for them
2906     // ---------------------------------------------------------
2907     bool checkBoundaryNodes = false;
2908     bool isQuadratic = false;
2909     set<const SMDS_MeshNode*> setMovableNodes;
2910     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2911     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2912     list< const SMDS_MeshElement* > elemsOnFace;
2913
2914     Extrema_GenExtPS projector;
2915     GeomAdaptor_Surface surfAdaptor;
2916     if ( !surface.IsNull() ) {
2917       surfAdaptor.Load( surface );
2918       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2919     }
2920     int nbElemOnFace = 0;
2921     itElem = theElems.begin();
2922     // loop on not yet smoothed elements: look for elems on a face
2923     while ( itElem != theElems.end() ) {
2924       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2925         break; // all elements found
2926
2927       const SMDS_MeshElement* elem = *itElem;
2928       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2929            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2930         ++itElem;
2931         continue;
2932       }
2933       elemsOnFace.push_back( elem );
2934       theElems.erase( itElem++ );
2935       nbElemOnFace++;
2936
2937       if ( !isQuadratic )
2938         isQuadratic = elem->IsQuadratic();
2939
2940       // get movable nodes of elem
2941       const SMDS_MeshNode* node;
2942       SMDS_TypeOfPosition posType;
2943       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2944       int nn = 0, nbn =  elem->NbNodes();
2945       if(elem->IsQuadratic())
2946         nbn = nbn/2;
2947       while ( nn++ < nbn ) {
2948         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2949         const SMDS_PositionPtr& pos = node->GetPosition();
2950         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2951         if (posType != SMDS_TOP_EDGE &&
2952             posType != SMDS_TOP_VERTEX &&
2953             theFixedNodes.find( node ) == theFixedNodes.end())
2954         {
2955           // check if all faces around the node are on faceSubMesh
2956           // because a node on edge may be bound to face
2957           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2958           bool all = true;
2959           if ( faceSubMesh ) {
2960             while ( eIt->more() && all ) {
2961               const SMDS_MeshElement* e = eIt->next();
2962               all = faceSubMesh->Contains( e );
2963             }
2964           }
2965           if ( all )
2966             setMovableNodes.insert( node );
2967           else
2968             checkBoundaryNodes = true;
2969         }
2970         if ( posType == SMDS_TOP_3DSPACE )
2971           checkBoundaryNodes = true;
2972       }
2973
2974       if ( surface.IsNull() )
2975         continue;
2976
2977       // get nodes to check UV
2978       list< const SMDS_MeshNode* > uvCheckNodes;
2979       itN = elem->nodesIterator();
2980       nn = 0; nbn =  elem->NbNodes();
2981       if(elem->IsQuadratic())
2982         nbn = nbn/2;
2983       while ( nn++ < nbn ) {
2984         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2985         if ( uvMap.find( node ) == uvMap.end() )
2986           uvCheckNodes.push_back( node );
2987         // add nodes of elems sharing node
2988         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2989         //         while ( eIt->more() ) {
2990         //           const SMDS_MeshElement* e = eIt->next();
2991         //           if ( e != elem ) {
2992         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2993         //             while ( nIt->more() ) {
2994         //               const SMDS_MeshNode* n =
2995         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2996         //               if ( uvMap.find( n ) == uvMap.end() )
2997         //                 uvCheckNodes.push_back( n );
2998         //             }
2999         //           }
3000         //         }
3001       }
3002       // check UV on face
3003       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3004       for ( ; n != uvCheckNodes.end(); ++n ) {
3005         node = *n;
3006         gp_XY uv( 0, 0 );
3007         const SMDS_PositionPtr& pos = node->GetPosition();
3008         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3009         // get existing UV
3010         switch ( posType ) {
3011         case SMDS_TOP_FACE: {
3012           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3013           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3014           break;
3015         }
3016         case SMDS_TOP_EDGE: {
3017           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3018           Handle(Geom2d_Curve) pcurve;
3019           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3020             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3021           if ( !pcurve.IsNull() ) {
3022             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3023             uv = pcurve->Value( u ).XY();
3024           }
3025           break;
3026         }
3027         case SMDS_TOP_VERTEX: {
3028           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3029           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3030             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3031           break;
3032         }
3033         default:;
3034         }
3035         // check existing UV
3036         bool project = true;
3037         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3038         double dist1 = DBL_MAX, dist2 = 0;
3039         if ( posType != SMDS_TOP_3DSPACE ) {
3040           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3041           project = dist1 > fToler2;
3042         }
3043         if ( project ) { // compute new UV
3044           gp_XY newUV;
3045           if ( !getClosestUV( projector, pNode, newUV )) {
3046             MESSAGE("Node Projection Failed " << node);
3047           }
3048           else {
3049             if ( isUPeriodic )
3050               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3051             if ( isVPeriodic )
3052               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3053             // check new UV
3054             if ( posType != SMDS_TOP_3DSPACE )
3055               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3056             if ( dist2 < dist1 )
3057               uv = newUV;
3058           }
3059         }
3060         // store UV in the map
3061         listUV.push_back( uv );
3062         uvMap.insert( make_pair( node, &listUV.back() ));
3063       }
3064     } // loop on not yet smoothed elements
3065
3066     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3067       checkBoundaryNodes = true;
3068
3069     // fix nodes on mesh boundary
3070
3071     if ( checkBoundaryNodes ) {
3072       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3073       map< NLink, int >::iterator link_nb;
3074       // put all elements links to linkNbMap
3075       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3076       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3077         const SMDS_MeshElement* elem = (*elemIt);
3078         int nbn =  elem->NbNodes();
3079         if(elem->IsQuadratic())
3080           nbn = nbn/2;
3081         // loop on elem links: insert them in linkNbMap
3082         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3083         for ( int iN = 0; iN < nbn; ++iN ) {
3084           curNode = elem->GetNode( iN );
3085           NLink link;
3086           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3087           else                      link = make_pair( prevNode , curNode );
3088           prevNode = curNode;
3089           link_nb = linkNbMap.find( link );
3090           if ( link_nb == linkNbMap.end() )
3091             linkNbMap.insert( make_pair ( link, 1 ));
3092           else
3093             link_nb->second++;
3094         }
3095       }
3096       // remove nodes that are in links encountered only once from setMovableNodes
3097       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3098         if ( link_nb->second == 1 ) {
3099           setMovableNodes.erase( link_nb->first.first );
3100           setMovableNodes.erase( link_nb->first.second );
3101         }
3102       }
3103     }
3104
3105     // -----------------------------------------------------
3106     // for nodes on seam edge, compute one more UV ( uvMap2 );
3107     // find movable nodes linked to nodes on seam and which
3108     // are to be smoothed using the second UV ( uvMap2 )
3109     // -----------------------------------------------------
3110
3111     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3112     if ( !surface.IsNull() ) {
3113       TopExp_Explorer eExp( face, TopAbs_EDGE );
3114       for ( ; eExp.More(); eExp.Next() ) {
3115         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3116         if ( !BRep_Tool::IsClosed( edge, face ))
3117           continue;
3118         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3119         if ( !sm ) continue;
3120         // find out which parameter varies for a node on seam
3121         double f,l;
3122         gp_Pnt2d uv1, uv2;
3123         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3124         if ( pcurve.IsNull() ) continue;
3125         uv1 = pcurve->Value( f );
3126         edge.Reverse();
3127         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3128         if ( pcurve.IsNull() ) continue;
3129         uv2 = pcurve->Value( f );
3130         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3131         // assure uv1 < uv2
3132         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3133           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3134         }
3135         // get nodes on seam and its vertices
3136         list< const SMDS_MeshNode* > seamNodes;
3137         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3138         while ( nSeamIt->more() ) {
3139           const SMDS_MeshNode* node = nSeamIt->next();
3140           if ( !isQuadratic || !IsMedium( node ))
3141             seamNodes.push_back( node );
3142         }
3143         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3144         for ( ; vExp.More(); vExp.Next() ) {
3145           sm = aMesh->MeshElements( vExp.Current() );
3146           if ( sm ) {
3147             nSeamIt = sm->GetNodes();
3148             while ( nSeamIt->more() )
3149               seamNodes.push_back( nSeamIt->next() );
3150           }
3151         }
3152         // loop on nodes on seam
3153         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3154         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3155           const SMDS_MeshNode* nSeam = *noSeIt;
3156           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3157           if ( n_uv == uvMap.end() )
3158             continue;
3159           // set the first UV
3160           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3161           // set the second UV
3162           listUV.push_back( *n_uv->second );
3163           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3164           if ( uvMap2.empty() )
3165             uvMap2 = uvMap; // copy the uvMap contents
3166           uvMap2[ nSeam ] = &listUV.back();
3167
3168           // collect movable nodes linked to ones on seam in nodesNearSeam
3169           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3170           while ( eIt->more() ) {
3171             const SMDS_MeshElement* e = eIt->next();
3172             int nbUseMap1 = 0, nbUseMap2 = 0;
3173             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3174             int nn = 0, nbn =  e->NbNodes();
3175             if(e->IsQuadratic()) nbn = nbn/2;
3176             while ( nn++ < nbn )
3177             {
3178               const SMDS_MeshNode* n =
3179                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3180               if (n == nSeam ||
3181                   setMovableNodes.find( n ) == setMovableNodes.end() )
3182                 continue;
3183               // add only nodes being closer to uv2 than to uv1
3184               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3185                            0.5 * ( n->Y() + nSeam->Y() ),
3186                            0.5 * ( n->Z() + nSeam->Z() ));
3187               gp_XY uv;
3188               getClosestUV( projector, pMid, uv );
3189               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3190                 nodesNearSeam.insert( n );
3191                 nbUseMap2++;
3192               }
3193               else
3194                 nbUseMap1++;
3195             }
3196             // for centroidalSmooth all element nodes must
3197             // be on one side of a seam
3198             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3199               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3200               nn = 0;
3201               while ( nn++ < nbn ) {
3202                 const SMDS_MeshNode* n =
3203                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3204                 setMovableNodes.erase( n );
3205               }
3206             }
3207           }
3208         } // loop on nodes on seam
3209       } // loop on edge of a face
3210     } // if ( !face.IsNull() )
3211
3212     if ( setMovableNodes.empty() ) {
3213       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3214       continue; // goto next face
3215     }
3216
3217     // -------------
3218     // SMOOTHING //
3219     // -------------
3220
3221     int it = -1;
3222     double maxRatio = -1., maxDisplacement = -1.;
3223     set<const SMDS_MeshNode*>::iterator nodeToMove;
3224     for ( it = 0; it < theNbIterations; it++ ) {
3225       maxDisplacement = 0.;
3226       nodeToMove = setMovableNodes.begin();
3227       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3228         const SMDS_MeshNode* node = (*nodeToMove);
3229         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3230
3231         // smooth
3232         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3233         if ( theSmoothMethod == LAPLACIAN )
3234           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3235         else
3236           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3237
3238         // node displacement
3239         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3240         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3241         if ( aDispl > maxDisplacement )
3242           maxDisplacement = aDispl;
3243       }
3244       // no node movement => exit
3245       //if ( maxDisplacement < 1.e-16 ) {
3246       if ( maxDisplacement < disttol ) {
3247         MESSAGE("-- no node movement --");
3248         break;
3249       }
3250
3251       // check elements quality
3252       maxRatio  = 0;
3253       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3254       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3255         const SMDS_MeshElement* elem = (*elemIt);
3256         if ( !elem || elem->GetType() != SMDSAbs_Face )
3257           continue;
3258         SMESH::Controls::TSequenceOfXYZ aPoints;
3259         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3260           double aValue = aQualityFunc.GetValue( aPoints );
3261           if ( aValue > maxRatio )
3262             maxRatio = aValue;
3263         }
3264       }
3265       if ( maxRatio <= theTgtAspectRatio ) {
3266         MESSAGE("-- quality achived --");
3267         break;
3268       }
3269       if (it+1 == theNbIterations) {
3270         MESSAGE("-- Iteration limit exceeded --");
3271       }
3272     } // smoothing iterations
3273
3274     MESSAGE(" Face id: " << *fId <<
3275             " Nb iterstions: " << it <<
3276             " Displacement: " << maxDisplacement <<
3277             " Aspect Ratio " << maxRatio);
3278
3279     // ---------------------------------------
3280     // new nodes positions are computed,
3281     // record movement in DS and set new UV
3282     // ---------------------------------------
3283     nodeToMove = setMovableNodes.begin();
3284     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3285       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3286       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3287       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3288       if ( node_uv != uvMap.end() ) {
3289         gp_XY* uv = node_uv->second;
3290         node->SetPosition
3291           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3292       }
3293     }
3294
3295     // move medium nodes of quadratic elements
3296     if ( isQuadratic )
3297     {
3298       SMESH_MesherHelper helper( *GetMesh() );
3299       if ( !face.IsNull() )
3300         helper.SetSubShape( face );
3301       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3302       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3303         const SMDS_VtkFace* QF =
3304           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3305         if(QF && QF->IsQuadratic()) {
3306           vector<const SMDS_MeshNode*> Ns;
3307           Ns.reserve(QF->NbNodes()+1);
3308           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3309           while ( anIter->more() )
3310             Ns.push_back( cast2Node(anIter->next()) );
3311           Ns.push_back( Ns[0] );
3312           double x, y, z;
3313           for(int i=0; i<QF->NbNodes(); i=i+2) {
3314             if ( !surface.IsNull() ) {
3315               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3316               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3317               gp_XY uv = ( uv1 + uv2 ) / 2.;
3318               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3319               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3320             }
3321             else {
3322               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3323               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3324               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3325             }
3326             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3327                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3328                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3329               // we have to move i+1 node
3330               aMesh->MoveNode( Ns[i+1], x, y, z );
3331             }
3332           }
3333         }
3334       }
3335     }
3336
3337   } // loop on face ids
3338
3339 }
3340
3341 //=======================================================================
3342 //function : isReverse
3343 //purpose  : Return true if normal of prevNodes is not co-directied with
3344 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3345 //           iNotSame is where prevNodes and nextNodes are different
3346 //=======================================================================
3347
3348 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3349                       vector<const SMDS_MeshNode*> nextNodes,
3350                       const int            nbNodes,
3351                       const int            iNotSame)
3352 {
3353   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3354   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3355
3356   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3357   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3358   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3359   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3360
3361   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3362   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3363   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3364   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3365
3366   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3367
3368   return (vA ^ vB) * vN < 0.0;
3369 }
3370
3371 //=======================================================================
3372 /*!
3373  * \brief Create elements by sweeping an element
3374  * \param elem - element to sweep
3375  * \param newNodesItVec - nodes generated from each node of the element
3376  * \param newElems - generated elements
3377  * \param nbSteps - number of sweeping steps
3378  * \param srcElements - to append elem for each generated element
3379  */
3380 //=======================================================================
3381
3382 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3383                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3384                                     list<const SMDS_MeshElement*>&        newElems,
3385                                     const int                             nbSteps,
3386                                     SMESH_SequenceOfElemPtr&              srcElements)
3387 {
3388   //MESSAGE("sweepElement " << nbSteps);
3389   SMESHDS_Mesh* aMesh = GetMeshDS();
3390
3391   // Loop on elem nodes:
3392   // find new nodes and detect same nodes indices
3393   int nbNodes = elem->NbNodes();
3394   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3395   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3396   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3397   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3398
3399   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3400   vector<int> sames(nbNodes);
3401   vector<bool> issimple(nbNodes);
3402
3403   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3404     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3405     const SMDS_MeshNode*                 node         = nnIt->first;
3406     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3407     if ( listNewNodes.empty() ) {
3408       return;
3409     }
3410
3411     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3412
3413     itNN[ iNode ] = listNewNodes.begin();
3414     prevNod[ iNode ] = node;
3415     nextNod[ iNode ] = listNewNodes.front();
3416     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3417       if ( prevNod[ iNode ] != nextNod [ iNode ])
3418         iNotSameNode = iNode;
3419       else {
3420         iSameNode = iNode;
3421         //nbSame++;
3422         sames[nbSame++] = iNode;
3423       }
3424     }
3425   }
3426
3427   //cerr<<"  nbSame = "<<nbSame<<endl;
3428   if ( nbSame == nbNodes || nbSame > 2) {
3429     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3430     //INFOS( " Too many same nodes of element " << elem->GetID() );
3431     return;
3432   }
3433
3434   //  if( elem->IsQuadratic() && nbSame>0 ) {
3435   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3436   //    return;
3437   //  }
3438
3439   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3440   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3441   if ( nbSame > 0 ) {
3442     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3443     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3444     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3445   }
3446
3447   //if(nbNodes==8)
3448   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3449   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3450   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3451   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3452
3453   // check element orientation
3454   int i0 = 0, i2 = 2;
3455   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3456     //MESSAGE("Reversed elem " << elem );
3457     i0 = 2;
3458     i2 = 0;
3459     if ( nbSame > 0 )
3460       std::swap( iBeforeSame, iAfterSame );
3461   }
3462
3463   // make new elements
3464   const SMDS_MeshElement* lastElem = elem;
3465   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3466     // get next nodes
3467     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3468       if(issimple[iNode]) {
3469         nextNod[ iNode ] = *itNN[ iNode ];
3470         itNN[ iNode ]++;
3471       }
3472       else {
3473         if( elem->GetType()==SMDSAbs_Node ) {
3474           // we have to use two nodes
3475           midlNod[ iNode ] = *itNN[ iNode ];
3476           itNN[ iNode ]++;
3477           nextNod[ iNode ] = *itNN[ iNode ];
3478           itNN[ iNode ]++;
3479         }
3480         else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3481           // we have to use each second node
3482           //itNN[ iNode ]++;
3483           nextNod[ iNode ] = *itNN[ iNode ];
3484           itNN[ iNode ]++;
3485         }
3486         else {
3487           // we have to use two nodes
3488           midlNod[ iNode ] = *itNN[ iNode ];
3489           itNN[ iNode ]++;
3490           nextNod[ iNode ] = *itNN[ iNode ];
3491           itNN[ iNode ]++;
3492         }
3493       }
3494     }
3495     SMDS_MeshElement* aNewElem = 0;
3496     if(!elem->IsPoly()) {
3497       switch ( nbNodes ) {
3498       case 0:
3499         return;
3500       case 1: { // NODE
3501         if ( nbSame == 0 ) {
3502           if(issimple[0])
3503             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3504           else
3505             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3506         }
3507         break;
3508       }
3509       case 2: { // EDGE
3510         if ( nbSame == 0 )
3511           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3512                                     nextNod[ 1 ], nextNod[ 0 ] );
3513         else
3514           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3515                                     nextNod[ iNotSameNode ] );
3516         break;
3517       }
3518
3519       case 3: { // TRIANGLE or quadratic edge
3520         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3521
3522           if ( nbSame == 0 )       // --- pentahedron
3523             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3524                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3525
3526           else if ( nbSame == 1 )  // --- pyramid
3527             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3528                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3529                                          nextNod[ iSameNode ]);
3530
3531           else // 2 same nodes:      --- tetrahedron
3532             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3533                                          nextNod[ iNotSameNode ]);
3534         }
3535         else { // quadratic edge
3536           if(nbSame==0) {     // quadratic quadrangle
3537             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3538                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3539           }
3540           else if(nbSame==1) { // quadratic triangle
3541             if(sames[0]==2) {
3542               return; // medium node on axis
3543             }
3544             else if(sames[0]==0) {
3545               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3546                                         nextNod[2], midlNod[1], prevNod[2]);
3547             }
3548             else { // sames[0]==1
3549               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3550                                         midlNod[0], nextNod[2], prevNod[2]);
3551             }
3552           }
3553           else {
3554             return;
3555           }
3556         }
3557         break;
3558       }
3559       case 4: { // QUADRANGLE
3560
3561         if ( nbSame == 0 )       // --- hexahedron
3562           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3563                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3564
3565         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3566           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3567                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3568                                        nextNod[ iSameNode ]);
3569           newElems.push_back( aNewElem );
3570           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3571                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3572                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3573         }
3574         else if ( nbSame == 2 ) { // pentahedron
3575           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3576             // iBeforeSame is same too
3577             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3578                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3579                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3580           else
3581             // iAfterSame is same too
3582             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3583                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3584                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3585         }
3586         break;
3587       }
3588       case 6: { // quadratic triangle
3589         // create pentahedron with 15 nodes
3590         if(nbSame==0) {
3591           if(i0>0) { // reversed case
3592             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3593                                          nextNod[0], nextNod[2], nextNod[1],
3594                                          prevNod[5], prevNod[4], prevNod[3],
3595                                          nextNod[5], nextNod[4], nextNod[3],
3596                                          midlNod[0], midlNod[2], midlNod[1]);
3597           }
3598           else { // not reversed case
3599             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3600                                          nextNod[0], nextNod[1], nextNod[2],
3601                                          prevNod[3], prevNod[4], prevNod[5],
3602                                          nextNod[3], nextNod[4], nextNod[5],
3603                                          midlNod[0], midlNod[1], midlNod[2]);
3604           }
3605         }
3606         else if(nbSame==1) {
3607           // 2d order pyramid of 13 nodes
3608           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3609           //                                 int n12,int n23,int n34,int n41,
3610           //                                 int n15,int n25,int n35,int n45, int ID);
3611           int n5 = iSameNode;
3612           int n1,n4,n41,n15,n45;
3613           if(i0>0) { // reversed case
3614             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3615             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3616             n41 = n1 + 3;
3617             n15 = n5 + 3;
3618             n45 = n4 + 3;
3619           }
3620           else {
3621             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3622             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3623             n41 = n4 + 3;
3624             n15 = n1 + 3;
3625             n45 = n5 + 3;
3626           }
3627           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3628                                       nextNod[n4], prevNod[n4], prevNod[n5],
3629                                       midlNod[n1], nextNod[n41],
3630                                       midlNod[n4], prevNod[n41],
3631                                       prevNod[n15], nextNod[n15],
3632                                       nextNod[n45], prevNod[n45]);
3633         }
3634         else if(nbSame==2) {
3635           // 2d order tetrahedron of 10 nodes
3636           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3637           //                                 int n12,int n23,int n31,
3638           //                                 int n14,int n24,int n34, int ID);
3639           int n1 = iNotSameNode;
3640           int n2,n3,n12,n23,n31;
3641           if(i0>0) { // reversed case
3642             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3643             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3644             n12 = n2 + 3;
3645             n23 = n3 + 3;
3646             n31 = n1 + 3;
3647           }
3648           else {
3649             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3650             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3651             n12 = n1 + 3;
3652             n23 = n2 + 3;
3653             n31 = n3 + 3;
3654           }
3655           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3656                                        prevNod[n12], prevNod[n23], prevNod[n31],
3657                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3658         }
3659         break;
3660       }
3661       case 8: { // quadratic quadrangle
3662         if(nbSame==0) {
3663           // create hexahedron with 20 nodes
3664           if(i0>0) { // reversed case
3665             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3666                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3667                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3668                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3669                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3670           }
3671           else { // not reversed case
3672             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3673                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3674                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3675                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3676                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3677           }
3678         }
3679         else if(nbSame==1) { 
3680           // --- pyramid + pentahedron - can not be created since it is needed 
3681           // additional middle node ot the center of face
3682           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3683           return;
3684         }
3685         else if(nbSame==2) {
3686           // 2d order Pentahedron with 15 nodes
3687           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3688           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3689           //                                 int n14,int n25,int n36, int ID);
3690           int n1,n2,n4,n5;
3691           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3692             // iBeforeSame is same too
3693             n1 = iBeforeSame;
3694             n2 = iOpposSame;
3695             n4 = iSameNode;
3696             n5 = iAfterSame;
3697           }
3698           else {
3699             // iAfterSame is same too
3700             n1 = iSameNode;
3701             n2 = iBeforeSame;
3702             n4 = iAfterSame;
3703             n5 = iOpposSame;
3704           }
3705           int n12,n45,n14,n25;
3706           if(i0>0) { //reversed case
3707             n12 = n1 + 4;
3708             n45 = n5 + 4;
3709             n14 = n4 + 4;
3710             n25 = n2 + 4;
3711           }
3712           else {
3713             n12 = n2 + 4;
3714             n45 = n4 + 4;
3715             n14 = n1 + 4;
3716             n25 = n5 + 4;
3717           }
3718           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3719                                        prevNod[n4], prevNod[n5], nextNod[n5],
3720                                        prevNod[n12], midlNod[n2], nextNod[n12],
3721                                        prevNod[n45], midlNod[n5], nextNod[n45],
3722                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3723         }
3724         break;
3725       }
3726       default: {
3727         // realized for extrusion only
3728         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3729         //vector<int> quantities (nbNodes + 2);
3730
3731         //quantities[0] = nbNodes; // bottom of prism
3732         //for (int inode = 0; inode < nbNodes; inode++) {
3733         //  polyedre_nodes[inode] = prevNod[inode];
3734         //}
3735
3736         //quantities[1] = nbNodes; // top of prism
3737         //for (int inode = 0; inode < nbNodes; inode++) {
3738         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3739         //}
3740
3741         //for (int iface = 0; iface < nbNodes; iface++) {
3742         //  quantities[iface + 2] = 4;
3743         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3744         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3745         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3746         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3747         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3748         //}
3749         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3750         break;
3751       }
3752       }
3753     }
3754
3755     if(!aNewElem) {
3756       // realized for extrusion only
3757       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3758       vector<int> quantities (nbNodes + 2);
3759
3760       quantities[0] = nbNodes; // bottom of prism
3761       for (int inode = 0; inode < nbNodes; inode++) {
3762         polyedre_nodes[inode] = prevNod[inode];
3763       }
3764
3765       quantities[1] = nbNodes; // top of prism
3766       for (int inode = 0; inode < nbNodes; inode++) {
3767         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3768       }
3769
3770       for (int iface = 0; iface < nbNodes; iface++) {
3771         quantities[iface + 2] = 4;
3772         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3773         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3774         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3775         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3776         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3777       }
3778       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3779     }
3780
3781     if ( aNewElem ) {
3782       newElems.push_back( aNewElem );
3783       myLastCreatedElems.Append(aNewElem);
3784       srcElements.Append( elem );
3785       lastElem = aNewElem;
3786     }
3787
3788     // set new prev nodes
3789     for ( iNode = 0; iNode < nbNodes; iNode++ )
3790       prevNod[ iNode ] = nextNod[ iNode ];
3791
3792   } // for steps
3793 }
3794
3795 //=======================================================================
3796 /*!
3797  * \brief Create 1D and 2D elements around swept elements
3798  * \param mapNewNodes - source nodes and ones generated from them
3799  * \param newElemsMap - source elements and ones generated from them
3800  * \param elemNewNodesMap - nodes generated from each node of each element
3801  * \param elemSet - all swept elements
3802  * \param nbSteps - number of sweeping steps
3803  * \param srcElements - to append elem for each generated element
3804  */
3805 //=======================================================================
3806
3807 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3808                                   TElemOfElemListMap &     newElemsMap,
3809                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3810                                   TIDSortedElemSet&        elemSet,
3811                                   const int                nbSteps,
3812                                   SMESH_SequenceOfElemPtr& srcElements)
3813 {
3814   MESSAGE("makeWalls");
3815   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3816   SMESHDS_Mesh* aMesh = GetMeshDS();
3817
3818   // Find nodes belonging to only one initial element - sweep them to get edges.
3819
3820   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3821   for ( ; nList != mapNewNodes.end(); nList++ ) {
3822     const SMDS_MeshNode* node =
3823       static_cast<const SMDS_MeshNode*>( nList->first );
3824     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3825     int nbInitElems = 0;
3826     const SMDS_MeshElement* el = 0;
3827     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3828     while ( eIt->more() && nbInitElems < 2 ) {
3829       el = eIt->next();
3830       SMDSAbs_ElementType type = el->GetType();
3831       if ( type == SMDSAbs_Volume || type < highType ) continue;
3832       if ( type > highType ) {
3833         nbInitElems = 0;
3834         highType = type;
3835       }
3836       if ( elemSet.find(el) != elemSet.end() )
3837         nbInitElems++;
3838     }
3839     if ( nbInitElems < 2 ) {
3840       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3841       if(!NotCreateEdge) {
3842         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3843         list<const SMDS_MeshElement*> newEdges;
3844         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3845       }
3846     }
3847   }
3848
3849   // Make a ceiling for each element ie an equal element of last new nodes.
3850   // Find free links of faces - make edges and sweep them into faces.
3851
3852   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3853   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3854   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3855     const SMDS_MeshElement* elem = itElem->first;
3856     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3857
3858     if ( elem->GetType() == SMDSAbs_Edge ) {
3859       // create a ceiling edge
3860       if (!elem->IsQuadratic()) {
3861         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3862                                vecNewNodes[ 1 ]->second.back())) {
3863           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3864                                                    vecNewNodes[ 1 ]->second.back()));
3865           srcElements.Append( myLastCreatedElems.Last() );
3866         }
3867       }
3868       else {
3869         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3870                                vecNewNodes[ 1 ]->second.back(),
3871                                vecNewNodes[ 2 ]->second.back())) {
3872           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3873                                                    vecNewNodes[ 1 ]->second.back(),
3874                                                    vecNewNodes[ 2 ]->second.back()));
3875           srcElements.Append( myLastCreatedElems.Last() );
3876         }
3877       }
3878     }
3879     if ( elem->GetType() != SMDSAbs_Face )
3880       continue;
3881
3882     if(itElem->second.size()==0) continue;
3883
3884     bool hasFreeLinks = false;
3885
3886     TIDSortedElemSet avoidSet;
3887     avoidSet.insert( elem );
3888
3889     set<const SMDS_MeshNode*> aFaceLastNodes;
3890     int iNode, nbNodes = vecNewNodes.size();
3891     if(!elem->IsQuadratic()) {
3892       // loop on the face nodes
3893       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3894         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3895         // look for free links of the face
3896         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3897         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3898         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3899         // check if a link is free
3900         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3901           hasFreeLinks = true;
3902           // make an edge and a ceiling for a new edge
3903           if ( !aMesh->FindEdge( n1, n2 )) {
3904             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3905             srcElements.Append( myLastCreatedElems.Last() );
3906           }
3907           n1 = vecNewNodes[ iNode ]->second.back();
3908           n2 = vecNewNodes[ iNext ]->second.back();
3909           if ( !aMesh->FindEdge( n1, n2 )) {
3910             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3911             srcElements.Append( myLastCreatedElems.Last() );
3912           }
3913         }
3914       }
3915     }
3916     else { // elem is quadratic face
3917       int nbn = nbNodes/2;
3918       for ( iNode = 0; iNode < nbn; iNode++ ) {
3919         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3920         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3921         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3922         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3923         // check if a link is free
3924         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3925           hasFreeLinks = true;
3926           // make an edge and a ceiling for a new edge
3927           // find medium node
3928           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3929           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3930             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3931             srcElements.Append( myLastCreatedElems.Last() );
3932           }
3933           n1 = vecNewNodes[ iNode ]->second.back();
3934           n2 = vecNewNodes[ iNext ]->second.back();
3935           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3936           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3937             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3938             srcElements.Append( myLastCreatedElems.Last() );
3939           }
3940         }
3941       }
3942       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3943         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3944       }
3945     }
3946
3947     // sweep free links into faces
3948
3949     if ( hasFreeLinks )  {
3950       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3951       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3952
3953       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3954       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3955         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3956         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3957       }
3958       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3959         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3960         iVol = 0;
3961         while ( iVol++ < volNb ) v++;
3962         // find indices of free faces of a volume and their source edges
3963         list< int > freeInd;
3964         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3965         SMDS_VolumeTool vTool( *v );
3966         int iF, nbF = vTool.NbFaces();
3967         for ( iF = 0; iF < nbF; iF ++ ) {
3968           if (vTool.IsFreeFace( iF ) &&
3969               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3970               initNodeSet != faceNodeSet) // except an initial face
3971           {
3972             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3973               continue;
3974             freeInd.push_back( iF );
3975             // find source edge of a free face iF
3976             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3977             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3978             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3979                                    initNodeSet.begin(), initNodeSet.end(),
3980                                    commonNodes.begin());
3981             if ( (*v)->IsQuadratic() )
3982               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3983             else
3984               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3985 #ifdef _DEBUG_
3986             if ( !srcEdges.back() )
3987             {
3988               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3989                    << iF << " of volume #" << vTool.ID() << endl;
3990             }
3991 #endif
3992           }
3993         }
3994         if ( freeInd.empty() )
3995           continue;
3996
3997         // create faces for all steps;
3998         // if such a face has been already created by sweep of edge,
3999         // assure that its orientation is OK
4000         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
4001           vTool.Set( *v );
4002           vTool.SetExternalNormal();
4003           list< int >::iterator ind = freeInd.begin();
4004           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4005           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4006           {
4007             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4008             int nbn = vTool.NbFaceNodes( *ind );
4009             switch ( nbn ) {
4010             case 3: { ///// triangle
4011               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4012               if ( !f )
4013                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4014               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4015                 {
4016                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4017                   aMesh->RemoveElement(f);
4018                 }
4019               break;
4020             }
4021             case 4: { ///// quadrangle
4022               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4023               if ( !f )
4024                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4025               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4026                 {
4027                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4028                   aMesh->RemoveElement(f);
4029                 }
4030               break;
4031             }
4032             default:
4033               if( (*v)->IsQuadratic() ) {
4034                 if(nbn==6) { /////// quadratic triangle
4035                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4036                                                              nodes[1], nodes[3], nodes[5] );
4037                   if ( !f ) {
4038                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4039                                                              nodes[1], nodes[3], nodes[5]));
4040                   }
4041                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4042                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4043                     tmpnodes[0] = nodes[0];
4044                     tmpnodes[1] = nodes[2];
4045                     tmpnodes[2] = nodes[4];
4046                     tmpnodes[3] = nodes[1];
4047                     tmpnodes[4] = nodes[3];
4048                     tmpnodes[5] = nodes[5];
4049                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4050                                                              nodes[1], nodes[3], nodes[5]));
4051                     aMesh->RemoveElement(f);
4052                   }
4053                 }
4054                 else {       /////// quadratic quadrangle
4055                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4056                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
4057                   if ( !f ) {
4058                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4059                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4060                   }
4061                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4062                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4063                     tmpnodes[0] = nodes[0];
4064                     tmpnodes[1] = nodes[2];
4065                     tmpnodes[2] = nodes[4];
4066                     tmpnodes[3] = nodes[6];
4067                     tmpnodes[4] = nodes[1];
4068                     tmpnodes[5] = nodes[3];
4069                     tmpnodes[6] = nodes[5];
4070                     tmpnodes[7] = nodes[7];
4071                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4072                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4073                     aMesh->RemoveElement(f);
4074                   }
4075                 }
4076               }
4077               else { //////// polygon
4078                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4079                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4080                 if ( !f )
4081                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4082                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4083                   {
4084                   // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4085                   MESSAGE("ChangeElementNodes");
4086                   aMesh->ChangeElementNodes( f, nodes, nbn );
4087                   }
4088               }
4089             }
4090             while ( srcElements.Length() < myLastCreatedElems.Length() )
4091               srcElements.Append( *srcEdge );
4092
4093           }  // loop on free faces
4094
4095           // go to the next volume
4096           iVol = 0;
4097           while ( iVol++ < nbVolumesByStep ) v++;
4098         }
4099       }
4100     } // sweep free links into faces
4101
4102     // Make a ceiling face with a normal external to a volume
4103
4104     SMDS_VolumeTool lastVol( itElem->second.back() );
4105
4106     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4107     if ( iF >= 0 ) {
4108       lastVol.SetExternalNormal();
4109       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4110       int nbn = lastVol.NbFaceNodes( iF );
4111       switch ( nbn ) {
4112       case 3:
4113         if (!hasFreeLinks ||
4114             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4115           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4116         break;
4117       case 4:
4118         if (!hasFreeLinks ||
4119             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4120           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4121         break;
4122       default:
4123         if(itElem->second.back()->IsQuadratic()) {
4124           if(nbn==6) {
4125             if (!hasFreeLinks ||
4126                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4127                                  nodes[1], nodes[3], nodes[5]) ) {
4128               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4129                                                        nodes[1], nodes[3], nodes[5]));
4130             }
4131           }
4132           else { // nbn==8
4133             if (!hasFreeLinks ||
4134                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4135                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4136               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4137                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4138           }
4139         }
4140         else {
4141           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4142           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4143             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4144         }
4145       } // switch
4146
4147       while ( srcElements.Length() < myLastCreatedElems.Length() )
4148         srcElements.Append( myLastCreatedElems.Last() );
4149     }
4150   } // loop on swept elements
4151 }
4152
4153 //=======================================================================
4154 //function : RotationSweep
4155 //purpose  :
4156 //=======================================================================
4157
4158 SMESH_MeshEditor::PGroupIDs
4159 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4160                                 const gp_Ax1&      theAxis,
4161                                 const double       theAngle,
4162                                 const int          theNbSteps,
4163                                 const double       theTol,
4164                                 const bool         theMakeGroups,
4165                                 const bool         theMakeWalls)
4166 {
4167   myLastCreatedElems.Clear();
4168   myLastCreatedNodes.Clear();
4169
4170   // source elements for each generated one
4171   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4172
4173   MESSAGE( "RotationSweep()");
4174   gp_Trsf aTrsf;
4175   aTrsf.SetRotation( theAxis, theAngle );
4176   gp_Trsf aTrsf2;
4177   aTrsf2.SetRotation( theAxis, theAngle/2. );
4178
4179   gp_Lin aLine( theAxis );
4180   double aSqTol = theTol * theTol;
4181
4182   SMESHDS_Mesh* aMesh = GetMeshDS();
4183
4184   TNodeOfNodeListMap mapNewNodes;
4185   TElemOfVecOfNnlmiMap mapElemNewNodes;
4186   TElemOfElemListMap newElemsMap;
4187
4188   // loop on theElems
4189   TIDSortedElemSet::iterator itElem;
4190   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4191     const SMDS_MeshElement* elem = *itElem;
4192     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4193       continue;
4194     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4195     newNodesItVec.reserve( elem->NbNodes() );
4196
4197     // loop on elem nodes
4198     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4199     while ( itN->more() ) {
4200       // check if a node has been already sweeped
4201       const SMDS_MeshNode* node = cast2Node( itN->next() );
4202
4203       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4204       double coord[3];
4205       aXYZ.Coord( coord[0], coord[1], coord[2] );
4206       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4207
4208       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4209       if ( nIt == mapNewNodes.end() ) {
4210         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4211         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4212
4213         // make new nodes
4214         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4215         //double coord[3];
4216         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4217         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4218         const SMDS_MeshNode * newNode = node;
4219         for ( int i = 0; i < theNbSteps; i++ ) {
4220           if ( !isOnAxis ) {
4221             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4222               // create two nodes
4223               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4224               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4225               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4226               myLastCreatedNodes.Append(newNode);
4227               srcNodes.Append( node );
4228               listNewNodes.push_back( newNode );
4229               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4230               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4231             }
4232             else {
4233               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4234             }
4235             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4236             myLastCreatedNodes.Append(newNode);
4237             srcNodes.Append( node );
4238             listNewNodes.push_back( newNode );
4239           }
4240           else {
4241             listNewNodes.push_back( newNode );
4242             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4243               listNewNodes.push_back( newNode );
4244             }
4245           }
4246         }
4247       }
4248       /*
4249         else {
4250         // if current elem is quadratic and current node is not medium
4251         // we have to check - may be it is needed to insert additional nodes
4252         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4253         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4254         if(listNewNodes.size()==theNbSteps) {
4255         listNewNodes.clear();
4256         // make new nodes
4257         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4258         //double coord[3];
4259         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4260         const SMDS_MeshNode * newNode = node;
4261         if ( !isOnAxis ) {
4262         for(int i = 0; i<theNbSteps; i++) {
4263         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4264         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4265         cout<<"    3 AddNode:  "<<newNode;
4266         myLastCreatedNodes.Append(newNode);
4267         listNewNodes.push_back( newNode );
4268         srcNodes.Append( node );
4269         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4270         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4271         cout<<"    4 AddNode:  "<<newNode;
4272         myLastCreatedNodes.Append(newNode);
4273         srcNodes.Append( node );
4274         listNewNodes.push_back( newNode );
4275         }
4276         }
4277         else {
4278         listNewNodes.push_back( newNode );
4279         }
4280         }
4281         }
4282         }
4283       */
4284       newNodesItVec.push_back( nIt );
4285     }
4286     // make new elements
4287     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4288   }
4289
4290   if ( theMakeWalls )
4291     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4292
4293   PGroupIDs newGroupIDs;
4294   if ( theMakeGroups )
4295     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4296
4297   return newGroupIDs;
4298 }
4299
4300
4301 //=======================================================================
4302 //function : CreateNode
4303 //purpose  :
4304 //=======================================================================
4305 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4306                                                   const double y,
4307                                                   const double z,
4308                                                   const double tolnode,
4309                                                   SMESH_SequenceOfNode& aNodes)
4310 {
4311   myLastCreatedElems.Clear();
4312   myLastCreatedNodes.Clear();
4313
4314   gp_Pnt P1(x,y,z);
4315   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4316
4317   // try to search in sequence of existing nodes
4318   // if aNodes.Length()>0 we 'nave to use given sequence
4319   // else - use all nodes of mesh
4320   if(aNodes.Length()>0) {
4321     int i;
4322     for(i=1; i<=aNodes.Length(); i++) {
4323       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4324       if(P1.Distance(P2)<tolnode)
4325         return aNodes.Value(i);
4326     }
4327   }
4328   else {
4329     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4330     while(itn->more()) {
4331       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4332       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4333       if(P1.Distance(P2)<tolnode)
4334         return aN;
4335     }
4336   }
4337
4338   // create new node and return it
4339   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4340   myLastCreatedNodes.Append(NewNode);
4341   return NewNode;
4342 }
4343
4344
4345 //=======================================================================
4346 //function : ExtrusionSweep
4347 //purpose  :
4348 //=======================================================================
4349
4350 SMESH_MeshEditor::PGroupIDs
4351 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4352                                   const gp_Vec&       theStep,
4353                                   const int           theNbSteps,
4354                                   TElemOfElemListMap& newElemsMap,
4355                                   const bool          theMakeGroups,
4356                                   const int           theFlags,
4357                                   const double        theTolerance)
4358 {
4359   ExtrusParam aParams;
4360   aParams.myDir = gp_Dir(theStep);
4361   aParams.myNodes.Clear();
4362   aParams.mySteps = new TColStd_HSequenceOfReal;
4363   int i;
4364   for(i=1; i<=theNbSteps; i++)
4365     aParams.mySteps->Append(theStep.Magnitude());
4366
4367   return
4368     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4369 }
4370
4371
4372 //=======================================================================
4373 //function : ExtrusionSweep
4374 //purpose  :
4375 //=======================================================================
4376
4377 SMESH_MeshEditor::PGroupIDs
4378 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4379                                   ExtrusParam&        theParams,
4380                                   TElemOfElemListMap& newElemsMap,
4381                                   const bool          theMakeGroups,
4382                                   const int           theFlags,
4383                                   const double        theTolerance)
4384 {
4385   MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4386   myLastCreatedElems.Clear();
4387   myLastCreatedNodes.Clear();
4388
4389   // source elements for each generated one
4390   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4391
4392   SMESHDS_Mesh* aMesh = GetMeshDS();
4393
4394   int nbsteps = theParams.mySteps->Length();
4395
4396   TNodeOfNodeListMap mapNewNodes;
4397   //TNodeOfNodeVecMap mapNewNodes;
4398   TElemOfVecOfNnlmiMap mapElemNewNodes;
4399   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4400
4401   // loop on theElems
4402   TIDSortedElemSet::iterator itElem;
4403   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4404     // check element type
4405     const SMDS_MeshElement* elem = *itElem;
4406     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4407       continue;
4408
4409     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4410     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4411     newNodesItVec.reserve( elem->NbNodes() );
4412
4413     // loop on elem nodes
4414     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4415     while ( itN->more() )
4416     {
4417       // check if a node has been already sweeped
4418       const SMDS_MeshNode* node = cast2Node( itN->next() );
4419       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4420       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4421       if ( nIt == mapNewNodes.end() ) {
4422         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4423         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4424         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4425         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4426         //vecNewNodes.reserve(nbsteps);
4427
4428         // make new nodes
4429         double coord[] = { node->X(), node->Y(), node->Z() };
4430         //int nbsteps = theParams.mySteps->Length();
4431         for ( int i = 0; i < nbsteps; i++ ) {
4432           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4433             // create additional node
4434             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4435             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4436             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4437             if( theFlags & EXTRUSION_FLAG_SEW ) {
4438               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4439                                                          theTolerance, theParams.myNodes);
4440               listNewNodes.push_back( newNode );
4441             }
4442             else {
4443               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4444               myLastCreatedNodes.Append(newNode);
4445               srcNodes.Append( node );
4446               listNewNodes.push_back( newNode );
4447             }
4448           }
4449           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4450           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4451           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4452           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4453           if( theFlags & EXTRUSION_FLAG_SEW ) {
4454             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4455                                                        theTolerance, theParams.myNodes);
4456             listNewNodes.push_back( newNode );
4457             //vecNewNodes[i]=newNode;
4458           }
4459           else {
4460             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4461             myLastCreatedNodes.Append(newNode);
4462             srcNodes.Append( node );
4463             listNewNodes.push_back( newNode );
4464             //vecNewNodes[i]=newNode;
4465           }
4466         }
4467       }
4468       else {
4469         // if current elem is quadratic and current node is not medium
4470         // we have to check - may be it is needed to insert additional nodes
4471         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4472           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4473           if(listNewNodes.size()==nbsteps) {
4474             listNewNodes.clear();
4475             double coord[] = { node->X(), node->Y(), node->Z() };
4476             for ( int i = 0; i < nbsteps; i++ ) {
4477               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4478               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4479               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4480               if( theFlags & EXTRUSION_FLAG_SEW ) {
4481                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4482                                                            theTolerance, theParams.myNodes);
4483                 listNewNodes.push_back( newNode );
4484               }
4485               else {
4486                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4487                 myLastCreatedNodes.Append(newNode);
4488                 srcNodes.Append( node );
4489                 listNewNodes.push_back( newNode );
4490               }
4491               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4492               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4493               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4494               if( theFlags & EXTRUSION_FLAG_SEW ) {
4495                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4496                                                            theTolerance, theParams.myNodes);
4497                 listNewNodes.push_back( newNode );
4498               }
4499               else {
4500                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4501                 myLastCreatedNodes.Append(newNode);
4502                 srcNodes.Append( node );
4503                 listNewNodes.push_back( newNode );
4504               }
4505             }
4506           }
4507         }
4508       }
4509       newNodesItVec.push_back( nIt );
4510     }
4511     // make new elements
4512     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4513   }
4514
4515   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4516     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4517   }
4518   PGroupIDs newGroupIDs;
4519   if ( theMakeGroups )
4520     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4521
4522   return newGroupIDs;
4523 }
4524
4525 /*
4526 //=======================================================================
4527 //class    : SMESH_MeshEditor_PathPoint
4528 //purpose  : auxiliary class
4529 //=======================================================================
4530 class SMESH_MeshEditor_PathPoint {
4531 public:
4532 SMESH_MeshEditor_PathPoint() {
4533 myPnt.SetCoord(99., 99., 99.);
4534 myTgt.SetCoord(1.,0.,0.);
4535 myAngle=0.;
4536 myPrm=0.;
4537 }
4538 void SetPnt(const gp_Pnt& aP3D){
4539 myPnt=aP3D;
4540 }
4541 void SetTangent(const gp_Dir& aTgt){
4542 myTgt=aTgt;
4543 }
4544 void SetAngle(const double& aBeta){
4545 myAngle=aBeta;
4546 }
4547 void SetParameter(const double& aPrm){
4548 myPrm=aPrm;
4549 }
4550 const gp_Pnt& Pnt()const{
4551 return myPnt;
4552 }
4553 const gp_Dir& Tangent()const{
4554 return myTgt;
4555 }
4556 double Angle()const{
4557 return myAngle;
4558 }
4559 double Parameter()const{
4560 return myPrm;
4561 }
4562
4563 protected:
4564 gp_Pnt myPnt;
4565 gp_Dir myTgt;
4566 double myAngle;
4567 double myPrm;
4568 };
4569 */
4570
4571 //=======================================================================
4572 //function : ExtrusionAlongTrack
4573 //purpose  :
4574 //=======================================================================
4575 SMESH_MeshEditor::Extrusion_Error
4576 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4577                                        SMESH_subMesh*       theTrack,
4578                                        const SMDS_MeshNode* theN1,
4579                                        const bool           theHasAngles,
4580                                        list<double>&        theAngles,
4581                                        const bool           theLinearVariation,
4582                                        const bool           theHasRefPoint,
4583                                        const gp_Pnt&        theRefPoint,
4584                                        const bool           theMakeGroups)
4585 {
4586   MESSAGE("ExtrusionAlongTrack");
4587   myLastCreatedElems.Clear();
4588   myLastCreatedNodes.Clear();
4589
4590   int aNbE;
4591   std::list<double> aPrms;
4592   TIDSortedElemSet::iterator itElem;
4593
4594   gp_XYZ aGC;
4595   TopoDS_Edge aTrackEdge;
4596   TopoDS_Vertex aV1, aV2;
4597
4598   SMDS_ElemIteratorPtr aItE;
4599   SMDS_NodeIteratorPtr aItN;
4600   SMDSAbs_ElementType aTypeE;
4601
4602   TNodeOfNodeListMap mapNewNodes;
4603
4604   // 1. Check data
4605   aNbE = theElements.size();
4606   // nothing to do
4607   if ( !aNbE )
4608     return EXTR_NO_ELEMENTS;
4609
4610   // 1.1 Track Pattern
4611   ASSERT( theTrack );
4612
4613   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4614
4615   aItE = pSubMeshDS->GetElements();
4616   while ( aItE->more() ) {
4617     const SMDS_MeshElement* pE = aItE->next();
4618     aTypeE = pE->GetType();
4619     // Pattern must contain links only
4620     if ( aTypeE != SMDSAbs_Edge )
4621       return EXTR_PATH_NOT_EDGE;
4622   }
4623
4624   list<SMESH_MeshEditor_PathPoint> fullList;
4625
4626   const TopoDS_Shape& aS = theTrack->GetSubShape();
4627   // Sub shape for the Pattern must be an Edge or Wire
4628   if( aS.ShapeType() == TopAbs_EDGE ) {
4629     aTrackEdge = TopoDS::Edge( aS );
4630     // the Edge must not be degenerated
4631     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4632       return EXTR_BAD_PATH_SHAPE;
4633     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4634     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4635     const SMDS_MeshNode* aN1 = aItN->next();
4636     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4637     const SMDS_MeshNode* aN2 = aItN->next();
4638     // starting node must be aN1 or aN2
4639     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4640       return EXTR_BAD_STARTING_NODE;
4641     aItN = pSubMeshDS->GetNodes();
4642     while ( aItN->more() ) {
4643       const SMDS_MeshNode* pNode = aItN->next();
4644       const SMDS_EdgePosition* pEPos =
4645         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4646       double aT = pEPos->GetUParameter();
4647       aPrms.push_back( aT );
4648     }
4649     //Extrusion_Error err =
4650     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4651   }
4652   else if( aS.ShapeType() == TopAbs_WIRE ) {
4653     list< SMESH_subMesh* > LSM;
4654     TopTools_SequenceOfShape Edges;
4655     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4656     while(itSM->more()) {
4657       SMESH_subMesh* SM = itSM->next();
4658       LSM.push_back(SM);
4659       const TopoDS_Shape& aS = SM->GetSubShape();
4660       Edges.Append(aS);
4661     }
4662     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4663     int startNid = theN1->GetID();
4664     TColStd_MapOfInteger UsedNums;
4665     int NbEdges = Edges.Length();
4666     int i = 1;
4667     for(; i<=NbEdges; i++) {
4668       int k = 0;
4669       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4670       for(; itLSM!=LSM.end(); itLSM++) {
4671         k++;
4672         if(UsedNums.Contains(k)) continue;
4673         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4674         SMESH_subMesh* locTrack = *itLSM;
4675         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4676         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4677         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4678         const SMDS_MeshNode* aN1 = aItN->next();
4679         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4680         const SMDS_MeshNode* aN2 = aItN->next();
4681         // starting node must be aN1 or aN2
4682         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4683         // 2. Collect parameters on the track edge
4684         aPrms.clear();
4685         aItN = locMeshDS->GetNodes();
4686         while ( aItN->more() ) {
4687           const SMDS_MeshNode* pNode = aItN->next();
4688           const SMDS_EdgePosition* pEPos =
4689             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4690           double aT = pEPos->GetUParameter();
4691           aPrms.push_back( aT );
4692         }
4693         list<SMESH_MeshEditor_PathPoint> LPP;
4694         //Extrusion_Error err =
4695         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4696         LLPPs.push_back(LPP);
4697         UsedNums.Add(k);
4698         // update startN for search following egde
4699         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4700         else startNid = aN1->GetID();
4701         break;
4702       }
4703     }
4704     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4705     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4706     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4707     for(; itPP!=firstList.end(); itPP++) {
4708       fullList.push_back( *itPP );
4709     }
4710     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4711     fullList.pop_back();
4712     itLLPP++;
4713     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4714       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4715       itPP = currList.begin();
4716       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4717       gp_Dir D1 = PP1.Tangent();
4718       gp_Dir D2 = PP2.Tangent();
4719       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4720                            (D1.Z()+D2.Z())/2 ) );
4721       PP1.SetTangent(Dnew);
4722       fullList.push_back(PP1);
4723       itPP++;
4724       for(; itPP!=firstList.end(); itPP++) {
4725         fullList.push_back( *itPP );
4726       }
4727       PP1 = fullList.back();
4728       fullList.pop_back();
4729     }
4730     // if wire not closed
4731     fullList.push_back(PP1);
4732     // else ???
4733   }
4734   else {
4735     return EXTR_BAD_PATH_SHAPE;
4736   }
4737
4738   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4739                           theHasRefPoint, theRefPoint, theMakeGroups);
4740 }
4741
4742
4743 //=======================================================================
4744 //function : ExtrusionAlongTrack
4745 //purpose  :
4746 //=======================================================================
4747 SMESH_MeshEditor::Extrusion_Error
4748 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4749                                        SMESH_Mesh*          theTrack,
4750                                        const SMDS_MeshNode* theN1,
4751                                        const bool           theHasAngles,
4752                                        list<double>&        theAngles,
4753                                        const bool           theLinearVariation,
4754                                        const bool           theHasRefPoint,
4755                                        const gp_Pnt&        theRefPoint,
4756                                        const bool           theMakeGroups)
4757 {
4758   myLastCreatedElems.Clear();
4759   myLastCreatedNodes.Clear();
4760
4761   int aNbE;
4762   std::list<double> aPrms;
4763   TIDSortedElemSet::iterator itElem;
4764
4765   gp_XYZ aGC;
4766   TopoDS_Edge aTrackEdge;
4767   TopoDS_Vertex aV1, aV2;
4768
4769   SMDS_ElemIteratorPtr aItE;
4770   SMDS_NodeIteratorPtr aItN;
4771   SMDSAbs_ElementType aTypeE;
4772
4773   TNodeOfNodeListMap mapNewNodes;
4774
4775   // 1. Check data
4776   aNbE = theElements.size();
4777   // nothing to do
4778   if ( !aNbE )
4779     return EXTR_NO_ELEMENTS;
4780
4781   // 1.1 Track Pattern
4782   ASSERT( theTrack );
4783
4784   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4785
4786   aItE = pMeshDS->elementsIterator();
4787   while ( aItE->more() ) {
4788     const SMDS_MeshElement* pE = aItE->next();
4789     aTypeE = pE->GetType();
4790     // Pattern must contain links only
4791     if ( aTypeE != SMDSAbs_Edge )
4792       return EXTR_PATH_NOT_EDGE;
4793   }
4794
4795   list<SMESH_MeshEditor_PathPoint> fullList;
4796
4797   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4798   // Sub shape for the Pattern must be an Edge or Wire
4799   if( aS.ShapeType() == TopAbs_EDGE ) {
4800     aTrackEdge = TopoDS::Edge( aS );
4801     // the Edge must not be degenerated
4802     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4803       return EXTR_BAD_PATH_SHAPE;
4804     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4805     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4806     const SMDS_MeshNode* aN1 = aItN->next();
4807     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4808     const SMDS_MeshNode* aN2 = aItN->next();
4809     // starting node must be aN1 or aN2
4810     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4811       return EXTR_BAD_STARTING_NODE;
4812     aItN = pMeshDS->nodesIterator();
4813     while ( aItN->more() ) {
4814       const SMDS_MeshNode* pNode = aItN->next();
4815       if( pNode==aN1 || pNode==aN2 ) continue;
4816       const SMDS_EdgePosition* pEPos =
4817         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4818       double aT = pEPos->GetUParameter();
4819       aPrms.push_back( aT );
4820     }
4821     //Extrusion_Error err =
4822     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4823   }
4824   else if( aS.ShapeType() == TopAbs_WIRE ) {
4825     list< SMESH_subMesh* > LSM;
4826     TopTools_SequenceOfShape Edges;
4827     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4828     for(; eExp.More(); eExp.Next()) {
4829       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4830       if( BRep_Tool::Degenerated(E) ) continue;
4831       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4832       if(SM) {
4833         LSM.push_back(SM);
4834         Edges.Append(E);
4835       }
4836     }
4837     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4838     int startNid = theN1->GetID();
4839     TColStd_MapOfInteger UsedNums;
4840     int NbEdges = Edges.Length();
4841     int i = 1;
4842     for(; i<=NbEdges; i++) {
4843       int k = 0;
4844       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4845       for(; itLSM!=LSM.end(); itLSM++) {
4846         k++;
4847         if(UsedNums.Contains(k)) continue;
4848         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4849         SMESH_subMesh* locTrack = *itLSM;
4850         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4851         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4852         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4853         const SMDS_MeshNode* aN1 = aItN->next();
4854         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4855         const SMDS_MeshNode* aN2 = aItN->next();
4856         // starting node must be aN1 or aN2
4857         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4858         // 2. Collect parameters on the track edge
4859         aPrms.clear();
4860         aItN = locMeshDS->GetNodes();
4861         while ( aItN->more() ) {
4862           const SMDS_MeshNode* pNode = aItN->next();
4863           const SMDS_EdgePosition* pEPos =
4864             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4865           double aT = pEPos->GetUParameter();
4866           aPrms.push_back( aT );
4867         }
4868         list<SMESH_MeshEditor_PathPoint> LPP;
4869         //Extrusion_Error err =
4870         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4871         LLPPs.push_back(LPP);
4872         UsedNums.Add(k);
4873         // update startN for search following egde
4874         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4875         else startNid = aN1->GetID();
4876         break;
4877       }
4878     }
4879     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4880     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4881     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4882     for(; itPP!=firstList.end(); itPP++) {
4883       fullList.push_back( *itPP );
4884     }
4885     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4886     fullList.pop_back();
4887     itLLPP++;
4888     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4889       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4890       itPP = currList.begin();
4891       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4892       gp_Pnt P1 = PP1.Pnt();
4893       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4894       gp_Pnt P2 = PP2.Pnt();
4895       gp_Dir D1 = PP1.Tangent();
4896       gp_Dir D2 = PP2.Tangent();
4897       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4898                            (D1.Z()+D2.Z())/2 ) );
4899       PP1.SetTangent(Dnew);
4900       fullList.push_back(PP1);
4901       itPP++;
4902       for(; itPP!=currList.end(); itPP++) {
4903         fullList.push_back( *itPP );
4904       }
4905       PP1 = fullList.back();
4906       fullList.pop_back();
4907     }
4908     // if wire not closed
4909     fullList.push_back(PP1);
4910     // else ???
4911   }
4912   else {
4913     return EXTR_BAD_PATH_SHAPE;
4914   }
4915
4916   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4917                           theHasRefPoint, theRefPoint, theMakeGroups);
4918 }
4919
4920
4921 //=======================================================================
4922 //function : MakeEdgePathPoints
4923 //purpose  : auxilary for ExtrusionAlongTrack
4924 //=======================================================================
4925 SMESH_MeshEditor::Extrusion_Error
4926 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4927                                      const TopoDS_Edge& aTrackEdge,
4928                                      bool FirstIsStart,
4929                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4930 {
4931   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4932   aTolVec=1.e-7;
4933   aTolVec2=aTolVec*aTolVec;
4934   double aT1, aT2;
4935   TopoDS_Vertex aV1, aV2;
4936   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4937   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4938   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4939   // 2. Collect parameters on the track edge
4940   aPrms.push_front( aT1 );
4941   aPrms.push_back( aT2 );
4942   // sort parameters
4943   aPrms.sort();
4944   if( FirstIsStart ) {
4945     if ( aT1 > aT2 ) {
4946       aPrms.reverse();
4947     }
4948   }
4949   else {
4950     if ( aT2 > aT1 ) {
4951       aPrms.reverse();
4952     }
4953   }
4954   // 3. Path Points
4955   SMESH_MeshEditor_PathPoint aPP;
4956   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4957   std::list<double>::iterator aItD = aPrms.begin();
4958   for(; aItD != aPrms.end(); ++aItD) {
4959     double aT = *aItD;
4960     gp_Pnt aP3D;
4961     gp_Vec aVec;
4962     aC3D->D1( aT, aP3D, aVec );
4963     aL2 = aVec.SquareMagnitude();
4964     if ( aL2 < aTolVec2 )
4965       return EXTR_CANT_GET_TANGENT;
4966     gp_Dir aTgt( aVec );
4967     aPP.SetPnt( aP3D );
4968     aPP.SetTangent( aTgt );
4969     aPP.SetParameter( aT );
4970     LPP.push_back(aPP);
4971   }
4972   return EXTR_OK;
4973 }
4974
4975
4976 //=======================================================================
4977 //function : MakeExtrElements
4978 //purpose  : auxilary for ExtrusionAlongTrack
4979 //=======================================================================
4980 SMESH_MeshEditor::Extrusion_Error
4981 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
4982                                    list<SMESH_MeshEditor_PathPoint>& fullList,
4983                                    const bool theHasAngles,
4984                                    list<double>& theAngles,
4985                                    const bool theLinearVariation,
4986                                    const bool theHasRefPoint,
4987                                    const gp_Pnt& theRefPoint,
4988                                    const bool theMakeGroups)
4989 {
4990   MESSAGE("MakeExtrElements");
4991   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
4992   int aNbTP = fullList.size();
4993   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4994   // Angles
4995   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4996     LinearAngleVariation(aNbTP-1, theAngles);
4997   }
4998   vector<double> aAngles( aNbTP );
4999   int j = 0;
5000   for(; j<aNbTP; ++j) {
5001     aAngles[j] = 0.;
5002   }
5003   if ( theHasAngles ) {
5004     double anAngle;;
5005     std::list<double>::iterator aItD = theAngles.begin();
5006     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5007       anAngle = *aItD;
5008       aAngles[j] = anAngle;
5009     }
5010   }
5011   // fill vector of path points with angles
5012   //aPPs.resize(fullList.size());
5013   j = -1;
5014   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5015   for(; itPP!=fullList.end(); itPP++) {
5016     j++;
5017     SMESH_MeshEditor_PathPoint PP = *itPP;
5018     PP.SetAngle(aAngles[j]);
5019     aPPs[j] = PP;
5020   }
5021
5022   TNodeOfNodeListMap mapNewNodes;
5023   TElemOfVecOfNnlmiMap mapElemNewNodes;
5024   TElemOfElemListMap newElemsMap;
5025   TIDSortedElemSet::iterator itElem;
5026   double aX, aY, aZ;
5027   int aNb;
5028   SMDSAbs_ElementType aTypeE;
5029   // source elements for each generated one
5030   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5031
5032   // 3. Center of rotation aV0
5033   gp_Pnt aV0 = theRefPoint;
5034   gp_XYZ aGC;
5035   if ( !theHasRefPoint ) {
5036     aNb = 0;
5037     aGC.SetCoord( 0.,0.,0. );
5038
5039     itElem = theElements.begin();
5040     for ( ; itElem != theElements.end(); itElem++ ) {
5041       const SMDS_MeshElement* elem = *itElem;
5042
5043       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5044       while ( itN->more() ) {
5045         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5046         aX = node->X();
5047         aY = node->Y();
5048         aZ = node->Z();
5049
5050         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5051           list<const SMDS_MeshNode*> aLNx;
5052           mapNewNodes[node] = aLNx;
5053           //
5054           gp_XYZ aXYZ( aX, aY, aZ );
5055           aGC += aXYZ;
5056           ++aNb;
5057         }
5058       }
5059     }
5060     aGC /= aNb;
5061     aV0.SetXYZ( aGC );
5062   } // if (!theHasRefPoint) {
5063   mapNewNodes.clear();
5064
5065   // 4. Processing the elements
5066   SMESHDS_Mesh* aMesh = GetMeshDS();
5067
5068   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5069     // check element type
5070     const SMDS_MeshElement* elem = *itElem;
5071     aTypeE = elem->GetType();
5072     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5073       continue;
5074
5075     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5076     newNodesItVec.reserve( elem->NbNodes() );
5077
5078     // loop on elem nodes
5079     int nodeIndex = -1;
5080     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5081     while ( itN->more() )
5082     {
5083       ++nodeIndex;
5084       // check if a node has been already processed
5085       const SMDS_MeshNode* node =
5086         static_cast<const SMDS_MeshNode*>( itN->next() );
5087       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5088       if ( nIt == mapNewNodes.end() ) {
5089         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5090         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5091
5092         // make new nodes
5093         aX = node->X();  aY = node->Y(); aZ = node->Z();
5094
5095         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5096         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5097         gp_Ax1 anAx1, anAxT1T0;
5098         gp_Dir aDT1x, aDT0x, aDT1T0;
5099
5100         aTolAng=1.e-4;
5101
5102         aV0x = aV0;
5103         aPN0.SetCoord(aX, aY, aZ);
5104
5105         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5106         aP0x = aPP0.Pnt();
5107         aDT0x= aPP0.Tangent();
5108         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5109
5110         for ( j = 1; j < aNbTP; ++j ) {
5111           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5112           aP1x = aPP1.Pnt();
5113           aDT1x = aPP1.Tangent();
5114           aAngle1x = aPP1.Angle();
5115
5116           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5117           // Translation
5118           gp_Vec aV01x( aP0x, aP1x );
5119           aTrsf.SetTranslation( aV01x );
5120
5121           // traslated point
5122           aV1x = aV0x.Transformed( aTrsf );
5123           aPN1 = aPN0.Transformed( aTrsf );
5124
5125           // rotation 1 [ T1,T0 ]
5126           aAngleT1T0=-aDT1x.Angle( aDT0x );
5127           if (fabs(aAngleT1T0) > aTolAng) {
5128             aDT1T0=aDT1x^aDT0x;
5129             anAxT1T0.SetLocation( aV1x );
5130             anAxT1T0.SetDirection( aDT1T0 );
5131             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5132
5133             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5134           }
5135
5136           // rotation 2
5137           if ( theHasAngles ) {
5138             anAx1.SetLocation( aV1x );
5139             anAx1.SetDirection( aDT1x );
5140             aTrsfRot.SetRotation( anAx1, aAngle1x );
5141
5142             aPN1 = aPN1.Transformed( aTrsfRot );
5143           }
5144
5145           // make new node
5146           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5147           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5148             // create additional node
5149             double x = ( aPN1.X() + aPN0.X() )/2.;
5150             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5151             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5152             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5153             myLastCreatedNodes.Append(newNode);
5154             srcNodes.Append( node );
5155             listNewNodes.push_back( newNode );
5156           }
5157           aX = aPN1.X();
5158           aY = aPN1.Y();
5159           aZ = aPN1.Z();
5160           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5161           myLastCreatedNodes.Append(newNode);
5162           srcNodes.Append( node );
5163           listNewNodes.push_back( newNode );
5164
5165           aPN0 = aPN1;
5166           aP0x = aP1x;
5167           aV0x = aV1x;
5168           aDT0x = aDT1x;
5169         }
5170       }
5171
5172       else {
5173         // if current elem is quadratic and current node is not medium
5174         // we have to check - may be it is needed to insert additional nodes
5175         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5176           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5177           if(listNewNodes.size()==aNbTP-1) {
5178             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5179             gp_XYZ P(node->X(), node->Y(), node->Z());
5180             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5181             int i;
5182             for(i=0; i<aNbTP-1; i++) {
5183               const SMDS_MeshNode* N = *it;
5184               double x = ( N->X() + P.X() )/2.;
5185               double y = ( N->Y() + P.Y() )/2.;
5186               double z = ( N->Z() + P.Z() )/2.;
5187               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5188               srcNodes.Append( node );
5189               myLastCreatedNodes.Append(newN);
5190               aNodes[2*i] = newN;
5191               aNodes[2*i+1] = N;
5192               P = gp_XYZ(N->X(),N->Y(),N->Z());
5193             }
5194             listNewNodes.clear();
5195             for(i=0; i<2*(aNbTP-1); i++) {
5196               listNewNodes.push_back(aNodes[i]);
5197             }
5198           }
5199         }
5200       }
5201
5202       newNodesItVec.push_back( nIt );
5203     }
5204     // make new elements
5205     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5206     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5207     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5208   }
5209
5210   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5211
5212   if ( theMakeGroups )
5213     generateGroups( srcNodes, srcElems, "extruded");
5214
5215   return EXTR_OK;
5216 }
5217
5218
5219 //=======================================================================
5220 //function : LinearAngleVariation
5221 //purpose  : auxilary for ExtrusionAlongTrack
5222 //=======================================================================
5223 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5224                                             list<double>& Angles)
5225 {
5226   int nbAngles = Angles.size();
5227   if( nbSteps > nbAngles ) {
5228     vector<double> theAngles(nbAngles);
5229     list<double>::iterator it = Angles.begin();
5230     int i = -1;
5231     for(; it!=Angles.end(); it++) {
5232       i++;
5233       theAngles[i] = (*it);
5234     }
5235     list<double> res;
5236     double rAn2St = double( nbAngles ) / double( nbSteps );
5237     double angPrev = 0, angle;
5238     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5239       double angCur = rAn2St * ( iSt+1 );
5240       double angCurFloor  = floor( angCur );
5241       double angPrevFloor = floor( angPrev );
5242       if ( angPrevFloor == angCurFloor )
5243         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5244       else {
5245         int iP = int( angPrevFloor );
5246         double angPrevCeil = ceil(angPrev);
5247         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5248
5249         int iC = int( angCurFloor );
5250         if ( iC < nbAngles )
5251           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5252
5253         iP = int( angPrevCeil );
5254         while ( iC-- > iP )
5255           angle += theAngles[ iC ];
5256       }
5257       res.push_back(angle);
5258       angPrev = angCur;
5259     }
5260     Angles.clear();
5261     it = res.begin();
5262     for(; it!=res.end(); it++)
5263       Angles.push_back( *it );
5264   }
5265 }
5266
5267
5268 //================================================================================
5269 /*!
5270  * \brief Move or copy theElements applying theTrsf to their nodes
5271  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5272  *  \param theTrsf - transformation to apply
5273  *  \param theCopy - if true, create translated copies of theElems
5274  *  \param theMakeGroups - if true and theCopy, create translated groups
5275  *  \param theTargetMesh - mesh to copy translated elements into
5276  *  \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5277  */
5278 //================================================================================
5279
5280 SMESH_MeshEditor::PGroupIDs
5281 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5282                              const gp_Trsf&     theTrsf,
5283                              const bool         theCopy,
5284                              const bool         theMakeGroups,
5285                              SMESH_Mesh*        theTargetMesh)
5286 {
5287   myLastCreatedElems.Clear();
5288   myLastCreatedNodes.Clear();
5289
5290   bool needReverse = false;
5291   string groupPostfix;
5292   switch ( theTrsf.Form() ) {
5293   case gp_PntMirror:
5294   case gp_Ax1Mirror:
5295   case gp_Ax2Mirror:
5296     needReverse = true;
5297     groupPostfix = "mirrored";
5298     break;
5299   case gp_Rotation:
5300     groupPostfix = "rotated";
5301     break;
5302   case gp_Translation:
5303     groupPostfix = "translated";
5304     break;
5305   case gp_Scale:
5306   case gp_CompoundTrsf: // different scale by axis
5307     groupPostfix = "scaled";
5308     break;
5309   default:
5310     needReverse = false;
5311     groupPostfix = "transformed";
5312   }
5313
5314   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5315   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5316   SMESHDS_Mesh* aMesh    = GetMeshDS();
5317
5318
5319   // map old node to new one
5320   TNodeNodeMap nodeMap;
5321
5322   // elements sharing moved nodes; those of them which have all
5323   // nodes mirrored but are not in theElems are to be reversed
5324   TIDSortedElemSet inverseElemSet;
5325
5326   // source elements for each generated one
5327   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5328
5329 //  // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5330 //  list<SMDS_MeshNode>          orphanCopy; // copies of orphan nodes
5331 //  vector<const SMDS_MeshNode*> orphanNode; // original orphan nodes
5332 //
5333 //  if ( theElems.empty() ) // transform the whole mesh
5334 //  {
5335 //    // add all elements
5336 //    SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5337 //    while ( eIt->more() ) theElems.insert( eIt->next() );
5338 //    // add orphan nodes
5339 //    SMDS_MeshElementIDFactory idFactory;
5340 //    SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5341 //    while ( nIt->more() )
5342 //    {
5343 //      const SMDS_MeshNode* node = nIt->next();
5344 //      if ( node->NbInverseElements() == 0 && !theElems.insert( node ).second )
5345 //      {
5346 //        // node was not inserted into theElems because an element with the same ID
5347 //        // is already there. As a work around we insert a copy of node with
5348 //        // an ID = -<index in orphanNode>
5349 //        orphanCopy.push_back( *node ); // copy node
5350 //        SMDS_MeshNode* nodeCopy = &orphanCopy.back();
5351 //        int uniqueID = -orphanNode.size();
5352 //        orphanNode.push_back( node );
5353 //        idFactory.BindID( uniqueID, nodeCopy );
5354 //        theElems.insert( nodeCopy );
5355 //      }
5356 //    }
5357 //  }
5358   // loop on theElems to transorm nodes
5359   TIDSortedElemSet::iterator itElem;
5360   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5361     const SMDS_MeshElement* elem = *itElem;
5362     if ( !elem )
5363       continue;
5364
5365     // loop on elem nodes
5366     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5367     while ( itN->more() ) {
5368
5369       const SMDS_MeshNode* node = cast2Node( itN->next() );
5370 //      if ( node->GetID() < 0 )
5371 //        node = orphanNode[ -node->GetID() ];
5372       // check if a node has been already transformed
5373       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5374         nodeMap.insert( make_pair ( node, node ));
5375       if ( !n2n_isnew.second )
5376         continue;
5377
5378       double coord[3];
5379       coord[0] = node->X();
5380       coord[1] = node->Y();
5381       coord[2] = node->Z();
5382       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5383       if ( theTargetMesh ) {
5384         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5385         n2n_isnew.first->second = newNode;
5386         myLastCreatedNodes.Append(newNode);
5387         srcNodes.Append( node );
5388       }
5389       else if ( theCopy ) {
5390         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5391         n2n_isnew.first->second = newNode;
5392         myLastCreatedNodes.Append(newNode);
5393         srcNodes.Append( node );
5394       }
5395       else {
5396         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5397         // node position on shape becomes invalid
5398         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5399           ( SMDS_SpacePosition::originSpacePosition() );
5400       }
5401
5402       // keep inverse elements
5403       if ( !theCopy && !theTargetMesh && needReverse ) {
5404         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5405         while ( invElemIt->more() ) {
5406           const SMDS_MeshElement* iel = invElemIt->next();
5407           inverseElemSet.insert( iel );
5408         }
5409       }
5410     }
5411   }
5412
5413   // either create new elements or reverse mirrored ones
5414   if ( !theCopy && !needReverse && !theTargetMesh )
5415     return PGroupIDs();
5416
5417   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5418   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5419     theElems.insert( *invElemIt );
5420
5421   // replicate or reverse elements
5422   // TODO revoir ordre reverse vtk
5423   enum {
5424     REV_TETRA   = 0,  //  = nbNodes - 4
5425     REV_PYRAMID = 1,  //  = nbNodes - 4
5426     REV_PENTA   = 2,  //  = nbNodes - 4
5427     REV_FACE    = 3,
5428     REV_HEXA    = 4,  //  = nbNodes - 4
5429     FORWARD     = 5
5430   };
5431   int index[][8] = {
5432     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5433     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5434     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5435     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5436     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5437     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5438   };
5439
5440   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5441   {
5442     const SMDS_MeshElement* elem = *itElem;
5443     if ( !elem || elem->GetType() == SMDSAbs_Node )
5444       continue;
5445
5446     int nbNodes = elem->NbNodes();
5447     int elemType = elem->GetType();
5448
5449     if (elem->IsPoly()) {
5450       // Polygon or Polyhedral Volume
5451       switch ( elemType ) {
5452       case SMDSAbs_Face:
5453         {
5454           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5455           int iNode = 0;
5456           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5457           while (itN->more()) {
5458             const SMDS_MeshNode* node =
5459               static_cast<const SMDS_MeshNode*>(itN->next());
5460             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5461             if (nodeMapIt == nodeMap.end())
5462               break; // not all nodes transformed
5463             if (needReverse) {
5464               // reverse mirrored faces and volumes
5465               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5466             } else {
5467               poly_nodes[iNode] = (*nodeMapIt).second;
5468             }
5469             iNode++;
5470           }
5471           if ( iNode != nbNodes )
5472             continue; // not all nodes transformed
5473
5474           if ( theTargetMesh ) {
5475             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5476             srcElems.Append( elem );
5477           }
5478           else if ( theCopy ) {
5479             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5480             srcElems.Append( elem );
5481           }
5482           else {
5483             aMesh->ChangePolygonNodes(elem, poly_nodes);
5484           }
5485         }
5486         break;
5487       case SMDSAbs_Volume:
5488         {
5489           // ATTENTION: Reversing is not yet done!!!
5490           const SMDS_VtkVolume* aPolyedre =
5491             dynamic_cast<const SMDS_VtkVolume*>( elem );
5492           if (!aPolyedre) {
5493             MESSAGE("Warning: bad volumic element");
5494             continue;
5495           }
5496
5497           vector<const SMDS_MeshNode*> poly_nodes;
5498           vector<int> quantities;
5499
5500           bool allTransformed = true;
5501           int nbFaces = aPolyedre->NbFaces();
5502           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5503             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5504             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5505               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5506               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5507               if (nodeMapIt == nodeMap.end()) {
5508                 allTransformed = false; // not all nodes transformed
5509               } else {
5510                 poly_nodes.push_back((*nodeMapIt).second);
5511               }
5512             }
5513             quantities.push_back(nbFaceNodes);
5514           }
5515           if ( !allTransformed )
5516             continue; // not all nodes transformed
5517
5518           if ( theTargetMesh ) {
5519             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5520             srcElems.Append( elem );
5521           }
5522           else if ( theCopy ) {
5523             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5524             srcElems.Append( elem );
5525           }
5526           else {
5527             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5528           }
5529         }
5530         break;
5531       default:;
5532       }
5533       continue;
5534     }
5535
5536     // Regular elements
5537     int* i = index[ FORWARD ];
5538     if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5539       if ( elemType == SMDSAbs_Face )
5540         i = index[ REV_FACE ];
5541       else
5542         i = index[ nbNodes - 4 ];
5543
5544     if(elem->IsQuadratic()) {
5545       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5546       i = anIds;
5547       if(needReverse) {
5548         if(nbNodes==3) { // quadratic edge
5549           static int anIds[] = {1,0,2};
5550           i = anIds;
5551         }
5552         else if(nbNodes==6) { // quadratic triangle
5553           static int anIds[] = {0,2,1,5,4,3};
5554           i = anIds;
5555         }
5556         else if(nbNodes==8) { // quadratic quadrangle
5557           static int anIds[] = {0,3,2,1,7,6,5,4};
5558           i = anIds;
5559         }
5560         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5561           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5562           i = anIds;
5563         }
5564         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5565           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5566           i = anIds;
5567         }
5568         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5569           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5570           i = anIds;
5571         }
5572         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5573           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5574           i = anIds;
5575         }
5576       }
5577     }
5578
5579     // find transformed nodes
5580     vector<const SMDS_MeshNode*> nodes(nbNodes);
5581     int iNode = 0;
5582     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5583     while ( itN->more() ) {
5584       const SMDS_MeshNode* node =
5585         static_cast<const SMDS_MeshNode*>( itN->next() );
5586       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5587       if ( nodeMapIt == nodeMap.end() )
5588         break; // not all nodes transformed
5589       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5590     }
5591     if ( iNode != nbNodes )
5592       continue; // not all nodes transformed
5593
5594     if ( theTargetMesh ) {
5595       if ( SMDS_MeshElement* copy =
5596            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5597         myLastCreatedElems.Append( copy );
5598         srcElems.Append( elem );
5599       }
5600     }
5601     else if ( theCopy ) {
5602       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5603         srcElems.Append( elem );
5604     }
5605     else {
5606       // reverse element as it was reversed by transformation
5607       if ( nbNodes > 2 )
5608         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5609     }
5610   }
5611
5612   PGroupIDs newGroupIDs;
5613
5614   if ( theMakeGroups && theCopy ||
5615        theMakeGroups && theTargetMesh )
5616     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5617
5618   return newGroupIDs;
5619 }
5620
5621
5622 ////=======================================================================
5623 ////function : Scale
5624 ////purpose  :
5625 ////=======================================================================
5626 //
5627 //SMESH_MeshEditor::PGroupIDs
5628 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5629 //                         const gp_Pnt&            thePoint,
5630 //                         const std::list<double>& theScaleFact,
5631 //                         const bool         theCopy,
5632 //                         const bool         theMakeGroups,
5633 //                         SMESH_Mesh*        theTargetMesh)
5634 //{
5635 //  MESSAGE("Scale");
5636 //  myLastCreatedElems.Clear();
5637 //  myLastCreatedNodes.Clear();
5638 //
5639 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5640 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5641 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
5642 //
5643 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5644 //  std::list<double>::const_iterator itS = theScaleFact.begin();
5645 //  scaleX = (*itS);
5646 //  if(theScaleFact.size()==1) {
5647 //    scaleY = (*itS);
5648 //    scaleZ= (*itS);
5649 //  }
5650 //  if(theScaleFact.size()==2) {
5651 //    itS++;
5652 //    scaleY = (*itS);
5653 //    scaleZ= (*itS);
5654 //  }
5655 //  if(theScaleFact.size()>2) {
5656 //    itS++;
5657 //    scaleY = (*itS);
5658 //    itS++;
5659 //    scaleZ= (*itS);
5660 //  }
5661 //
5662 //  // map old node to new one
5663 //  TNodeNodeMap nodeMap;
5664 //
5665 //  // elements sharing moved nodes; those of them which have all
5666 //  // nodes mirrored but are not in theElems are to be reversed
5667 //  TIDSortedElemSet inverseElemSet;
5668 //
5669 //  // source elements for each generated one
5670 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
5671 //
5672 //  // loop on theElems
5673 //  TIDSortedElemSet::iterator itElem;
5674 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5675 //    const SMDS_MeshElement* elem = *itElem;
5676 //    if ( !elem )
5677 //      continue;
5678 //
5679 //    // loop on elem nodes
5680 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5681 //    while ( itN->more() ) {
5682 //
5683 //      // check if a node has been already transformed
5684 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
5685 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5686 //        nodeMap.insert( make_pair ( node, node ));
5687 //      if ( !n2n_isnew.second )
5688 //        continue;
5689 //
5690 //      //double coord[3];
5691 //      //coord[0] = node->X();
5692 //      //coord[1] = node->Y();
5693 //      //coord[2] = node->Z();
5694 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5695 //      double dx = (node->X() - thePoint.X()) * scaleX;
5696 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
5697 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
5698 //      if ( theTargetMesh ) {
5699 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5700 //        const SMDS_MeshNode * newNode =
5701 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5702 //        n2n_isnew.first->second = newNode;
5703 //        myLastCreatedNodes.Append(newNode);
5704 //        srcNodes.Append( node );
5705 //      }
5706 //      else if ( theCopy ) {
5707 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5708 //        const SMDS_MeshNode * newNode =
5709 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5710 //        n2n_isnew.first->second = newNode;
5711 //        myLastCreatedNodes.Append(newNode);
5712 //        srcNodes.Append( node );
5713 //      }
5714 //      else {
5715 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5716 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5717 //        // node position on shape becomes invalid
5718 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
5719 //          ( SMDS_SpacePosition::originSpacePosition() );
5720 //      }
5721 //
5722 //      // keep inverse elements
5723 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
5724 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5725 //      //  while ( invElemIt->more() ) {
5726 //      //    const SMDS_MeshElement* iel = invElemIt->next();
5727 //      //    inverseElemSet.insert( iel );
5728 //      //  }
5729 //      //}
5730 //    }
5731 //  }
5732 //
5733 //  // either create new elements or reverse mirrored ones
5734 //  //if ( !theCopy && !needReverse && !theTargetMesh )
5735 //  if ( !theCopy && !theTargetMesh )
5736 //    return PGroupIDs();
5737 //
5738 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5739 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5740 //    theElems.insert( *invElemIt );
5741 //
5742 //  // replicate or reverse elements
5743 //
5744 //  enum {
5745 //    REV_TETRA   = 0,  //  = nbNodes - 4
5746 //    REV_PYRAMID = 1,  //  = nbNodes - 4
5747 //    REV_PENTA   = 2,  //  = nbNodes - 4
5748 //    REV_FACE    = 3,
5749 //    REV_HEXA    = 4,  //  = nbNodes - 4
5750 //    FORWARD     = 5
5751 //  };
5752 //  int index[][8] = {
5753 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5754 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5755 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5756 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5757 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5758 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5759 //  };
5760 //
5761 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5762 //  {
5763 //    const SMDS_MeshElement* elem = *itElem;
5764 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
5765 //      continue;
5766 //
5767 //    int nbNodes = elem->NbNodes();
5768 //    int elemType = elem->GetType();
5769 //
5770 //    if (elem->IsPoly()) {
5771 //      // Polygon or Polyhedral Volume
5772 //      switch ( elemType ) {
5773 //      case SMDSAbs_Face:
5774 //        {
5775 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5776 //          int iNode = 0;
5777 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5778 //          while (itN->more()) {
5779 //            const SMDS_MeshNode* node =
5780 //              static_cast<const SMDS_MeshNode*>(itN->next());
5781 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5782 //            if (nodeMapIt == nodeMap.end())
5783 //              break; // not all nodes transformed
5784 //            //if (needReverse) {
5785 //            //  // reverse mirrored faces and volumes
5786 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5787 //            //} else {
5788 //            poly_nodes[iNode] = (*nodeMapIt).second;
5789 //            //}
5790 //            iNode++;
5791 //          }
5792 //          if ( iNode != nbNodes )
5793 //            continue; // not all nodes transformed
5794 //
5795 //          if ( theTargetMesh ) {
5796 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5797 //            srcElems.Append( elem );
5798 //          }
5799 //          else if ( theCopy ) {
5800 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5801 //            srcElems.Append( elem );
5802 //          }
5803 //          else {
5804 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
5805 //          }
5806 //        }
5807 //        break;
5808 //      case SMDSAbs_Volume:
5809 //        {
5810 //          // ATTENTION: Reversing is not yet done!!!
5811 //          const SMDS_VtkVolume* aPolyedre =
5812 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
5813 //          if (!aPolyedre) {
5814 //            MESSAGE("Warning: bad volumic element");
5815 //            continue;
5816 //          }
5817 //
5818 //          vector<const SMDS_MeshNode*> poly_nodes;
5819 //          vector<int> quantities;
5820 //
5821 //          bool allTransformed = true;
5822 //          int nbFaces = aPolyedre->NbFaces();
5823 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5824 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5825 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5826 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5827 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5828 //              if (nodeMapIt == nodeMap.end()) {
5829 //                allTransformed = false; // not all nodes transformed
5830 //              } else {
5831 //                poly_nodes.push_back((*nodeMapIt).second);
5832 //              }
5833 //            }
5834 //            quantities.push_back(nbFaceNodes);
5835 //          }
5836 //          if ( !allTransformed )
5837 //            continue; // not all nodes transformed
5838 //
5839 //          if ( theTargetMesh ) {
5840 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5841 //            srcElems.Append( elem );
5842 //          }
5843 //          else if ( theCopy ) {
5844 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5845 //            srcElems.Append( elem );
5846 //          }
5847 //          else {
5848 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5849 //          }
5850 //        }
5851 //        break;
5852 //      default:;
5853 //      }
5854 //      continue;
5855 //    }
5856 //
5857 //    // Regular elements
5858 //    int* i = index[ FORWARD ];
5859 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5860 //    //  if ( elemType == SMDSAbs_Face )
5861 //    //    i = index[ REV_FACE ];
5862 //    //  else
5863 //    //    i = index[ nbNodes - 4 ];
5864 //
5865 //    if(elem->IsQuadratic()) {
5866 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5867 //      i = anIds;
5868 //      //if(needReverse) {
5869 //      //  if(nbNodes==3) { // quadratic edge
5870 //      //    static int anIds[] = {1,0,2};
5871 //      //    i = anIds;
5872 //      //  }
5873 //      //  else if(nbNodes==6) { // quadratic triangle
5874 //      //    static int anIds[] = {0,2,1,5,4,3};
5875 //      //    i = anIds;
5876 //      //  }
5877 //      //  else if(nbNodes==8) { // quadratic quadrangle
5878 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
5879 //      //    i = anIds;
5880 //      //  }
5881 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5882 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5883 //      //    i = anIds;
5884 //      //  }
5885 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5886 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5887 //      //    i = anIds;
5888 //      //  }
5889 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5890 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5891 //      //    i = anIds;
5892 //      //  }
5893 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5894 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5895 //      //    i = anIds;
5896 //      //  }
5897 //      //}
5898 //    }
5899 //
5900 //    // find transformed nodes
5901 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
5902 //    int iNode = 0;
5903 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5904 //    while ( itN->more() ) {
5905 //      const SMDS_MeshNode* node =
5906 //        static_cast<const SMDS_MeshNode*>( itN->next() );
5907 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5908 //      if ( nodeMapIt == nodeMap.end() )
5909 //        break; // not all nodes transformed
5910 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5911 //    }
5912 //    if ( iNode != nbNodes )
5913 //      continue; // not all nodes transformed
5914 //
5915 //    if ( theTargetMesh ) {
5916 //      if ( SMDS_MeshElement* copy =
5917 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5918 //        myLastCreatedElems.Append( copy );
5919 //        srcElems.Append( elem );
5920 //      }
5921 //    }
5922 //    else if ( theCopy ) {
5923 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5924 //        myLastCreatedElems.Append( copy );
5925 //        srcElems.Append( elem );
5926 //      }
5927 //    }
5928 //    else {
5929 //      // reverse element as it was reversed by transformation
5930 //      if ( nbNodes > 2 )
5931 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5932 //    }
5933 //  }
5934 //
5935 //  PGroupIDs newGroupIDs;
5936 //
5937 //  if ( theMakeGroups && theCopy ||
5938 //       theMakeGroups && theTargetMesh ) {
5939 //    string groupPostfix = "scaled";
5940 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5941 //  }
5942 //
5943 //  return newGroupIDs;
5944 //}
5945
5946
5947 //=======================================================================
5948 /*!
5949  * \brief Create groups of elements made during transformation
5950  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5951  * \param elemGens - elements making corresponding myLastCreatedElems
5952  * \param postfix - to append to names of new groups
5953  */
5954 //=======================================================================
5955
5956 SMESH_MeshEditor::PGroupIDs
5957 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5958                                  const SMESH_SequenceOfElemPtr& elemGens,
5959                                  const std::string&             postfix,
5960                                  SMESH_Mesh*                    targetMesh)
5961 {
5962   PGroupIDs newGroupIDs( new list<int> );
5963   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5964
5965   // Sort existing groups by types and collect their names
5966
5967   // to store an old group and a generated new one
5968   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5969   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5970   // group names
5971   set< string > groupNames;
5972   //
5973   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5974   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5975   while ( groupIt->more() ) {
5976     SMESH_Group * group = groupIt->next();
5977     if ( !group ) continue;
5978     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5979     if ( !groupDS || groupDS->IsEmpty() ) continue;
5980     groupNames.insert( group->GetName() );
5981     groupDS->SetStoreName( group->GetName() );
5982     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5983   }
5984
5985   // Groups creation
5986
5987   // loop on nodes and elements
5988   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5989   {
5990     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5991     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5992     if ( gens.Length() != elems.Length() )
5993       throw SALOME_Exception(LOCALIZED("invalid args"));
5994
5995     // loop on created elements
5996     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5997     {
5998       const SMDS_MeshElement* sourceElem = gens( iElem );
5999       if ( !sourceElem ) {
6000         MESSAGE("generateGroups(): NULL source element");
6001         continue;
6002       }
6003       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6004       if ( groupsOldNew.empty() ) {
6005         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6006           ++iElem; // skip all elements made by sourceElem
6007         continue;
6008       }
6009       // collect all elements made by sourceElem
6010       list< const SMDS_MeshElement* > resultElems;
6011       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6012         if ( resElem != sourceElem )
6013           resultElems.push_back( resElem );
6014       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6015         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6016           if ( resElem != sourceElem )
6017             resultElems.push_back( resElem );
6018       // do not generate element groups from node ones
6019       if ( sourceElem->GetType() == SMDSAbs_Node &&
6020            elems( iElem )->GetType() != SMDSAbs_Node )
6021         continue;
6022
6023       // add resultElems to groups made by ones the sourceElem belongs to
6024       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6025       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6026       {
6027         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6028         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6029         {
6030           SMDS_MeshGroup* & newGroup = gOldNew->second;
6031           if ( !newGroup )// create a new group
6032           {
6033             // make a name
6034             string name = oldGroup->GetStoreName();
6035             if ( !targetMesh ) {
6036               name += "_";
6037               name += postfix;
6038               int nb = 0;
6039               while ( !groupNames.insert( name ).second ) // name exists
6040               {
6041                 if ( nb == 0 ) {
6042                   name += "_1";
6043                 }
6044                 else {
6045                   TCollection_AsciiString nbStr(nb+1);
6046                   name.resize( name.rfind('_')+1 );
6047                   name += nbStr.ToCString();
6048                 }
6049                 ++nb;
6050               }
6051             }
6052             // make a group
6053             int id;
6054             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6055                                                  name.c_str(), id );
6056             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6057             newGroup = & groupDS->SMDSGroup();
6058             newGroupIDs->push_back( id );
6059           }
6060
6061           // fill in a new group
6062           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6063           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6064             newGroup->Add( *resElemIt );
6065         }
6066       }
6067     } // loop on created elements
6068   }// loop on nodes and elements
6069
6070   return newGroupIDs;
6071 }
6072
6073 //================================================================================
6074 /*!
6075  * \brief Return list of group of nodes close to each other within theTolerance
6076  *        Search among theNodes or in the whole mesh if theNodes is empty using
6077  *        an Octree algorithm
6078  */
6079 //================================================================================
6080
6081 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6082                                             const double         theTolerance,
6083                                             TListOfListOfNodes & theGroupsOfNodes)
6084 {
6085   myLastCreatedElems.Clear();
6086   myLastCreatedNodes.Clear();
6087
6088   if ( theNodes.empty() )
6089   { // get all nodes in the mesh
6090     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6091     while ( nIt->more() )
6092       theNodes.insert( theNodes.end(),nIt->next());
6093   }
6094
6095   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6096 }
6097
6098
6099 //=======================================================================
6100 /*!
6101  * \brief Implementation of search for the node closest to point
6102  */
6103 //=======================================================================
6104
6105 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6106 {
6107   //---------------------------------------------------------------------
6108   /*!
6109    * \brief Constructor
6110    */
6111   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6112   {
6113     myMesh = ( SMESHDS_Mesh* ) theMesh;
6114
6115     TIDSortedNodeSet nodes;
6116     if ( theMesh ) {
6117       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6118       while ( nIt->more() )
6119         nodes.insert( nodes.end(), nIt->next() );
6120     }
6121     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6122
6123     // get max size of a leaf box
6124     SMESH_OctreeNode* tree = myOctreeNode;
6125     while ( !tree->isLeaf() )
6126     {
6127       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6128       if ( cIt->more() )
6129         tree = cIt->next();
6130     }
6131     myHalfLeafSize = tree->maxSize() / 2.;
6132   }
6133
6134   //---------------------------------------------------------------------
6135   /*!
6136    * \brief Move node and update myOctreeNode accordingly
6137    */
6138   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6139   {
6140     myOctreeNode->UpdateByMoveNode( node, toPnt );
6141     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6142   }
6143
6144   //---------------------------------------------------------------------
6145   /*!
6146    * \brief Do it's job
6147    */
6148   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6149   {
6150     map<double, const SMDS_MeshNode*> dist2Nodes;
6151     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6152     if ( !dist2Nodes.empty() )
6153       return dist2Nodes.begin()->second;
6154     list<const SMDS_MeshNode*> nodes;
6155     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6156
6157     double minSqDist = DBL_MAX;
6158     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6159     {
6160       // sort leafs by their distance from thePnt
6161       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6162       TDistTreeMap treeMap;
6163       list< SMESH_OctreeNode* > treeList;
6164       list< SMESH_OctreeNode* >::iterator trIt;
6165       treeList.push_back( myOctreeNode );
6166
6167       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6168       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6169       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6170       {
6171         SMESH_OctreeNode* tree = *trIt;
6172         if ( !tree->isLeaf() ) // put children to the queue
6173         {
6174           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6175           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6176           while ( cIt->more() )
6177             treeList.push_back( cIt->next() );
6178         }
6179         else if ( tree->NbNodes() ) // put a tree to the treeMap
6180         {
6181           const Bnd_B3d& box = tree->getBox();
6182           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6183           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6184           if ( !it_in.second ) // not unique distance to box center
6185             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6186         }
6187       }
6188       // find distance after which there is no sense to check tree's
6189       double sqLimit = DBL_MAX;
6190       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6191       if ( treeMap.size() > 5 ) {
6192         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6193         const Bnd_B3d& box = closestTree->getBox();
6194         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6195         sqLimit = limit * limit;
6196       }
6197       // get all nodes from trees
6198       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6199         if ( sqDist_tree->first > sqLimit )
6200           break;
6201         SMESH_OctreeNode* tree = sqDist_tree->second;
6202         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6203       }
6204     }
6205     // find closest among nodes
6206     minSqDist = DBL_MAX;
6207     const SMDS_MeshNode* closestNode = 0;
6208     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6209     for ( ; nIt != nodes.end(); ++nIt ) {
6210       double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6211       if ( minSqDist > sqDist ) {
6212         closestNode = *nIt;
6213         minSqDist = sqDist;
6214       }
6215     }
6216     return closestNode;
6217   }
6218
6219   //---------------------------------------------------------------------
6220   /*!
6221    * \brief Destructor
6222    */
6223   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6224
6225   //---------------------------------------------------------------------
6226   /*!
6227    * \brief Return the node tree
6228    */
6229   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6230
6231 private:
6232   SMESH_OctreeNode* myOctreeNode;
6233   SMESHDS_Mesh*     myMesh;
6234   double            myHalfLeafSize; // max size of a leaf box
6235 };
6236
6237 //=======================================================================
6238 /*!
6239  * \brief Return SMESH_NodeSearcher
6240  */
6241 //=======================================================================
6242
6243 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6244 {
6245   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6246 }
6247
6248 // ========================================================================
6249 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6250 {
6251   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6252   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6253   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6254
6255   //=======================================================================
6256   /*!
6257    * \brief Octal tree of bounding boxes of elements
6258    */
6259   //=======================================================================
6260
6261   class ElementBndBoxTree : public SMESH_Octree
6262   {
6263   public:
6264
6265     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius );
6266     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6267     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6268     ~ElementBndBoxTree();
6269
6270   protected:
6271     ElementBndBoxTree() {}
6272     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6273     void buildChildrenData();
6274     Bnd_B3d* buildRootBox();
6275   private:
6276     //!< Bounding box of element
6277     struct ElementBox : public Bnd_B3d
6278     {
6279       const SMDS_MeshElement* _element;
6280       int                     _refCount; // an ElementBox can be included in several tree branches
6281       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6282     };
6283     vector< ElementBox* > _elements;
6284   };
6285
6286   //================================================================================
6287   /*!
6288    * \brief ElementBndBoxTree creation
6289    */
6290   //================================================================================
6291
6292   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance)
6293     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6294   {
6295     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6296     _elements.reserve( nbElems );
6297
6298     SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
6299     while ( elemIt->more() )
6300       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6301
6302     if ( _elements.size() > MaxNbElemsInLeaf )
6303       compute();
6304     else
6305       myIsLeaf = true;
6306   }
6307
6308   //================================================================================
6309   /*!
6310    * \brief Destructor
6311    */
6312   //================================================================================
6313
6314   ElementBndBoxTree::~ElementBndBoxTree()
6315   {
6316     for ( int i = 0; i < _elements.size(); ++i )
6317       if ( --_elements[i]->_refCount <= 0 )
6318         delete _elements[i];
6319   }
6320
6321   //================================================================================
6322   /*!
6323    * \brief Return the maximal box
6324    */
6325   //================================================================================
6326
6327   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6328   {
6329     Bnd_B3d* box = new Bnd_B3d;
6330     for ( int i = 0; i < _elements.size(); ++i )
6331       box->Add( *_elements[i] );
6332     return box;
6333   }
6334
6335   //================================================================================
6336   /*!
6337    * \brief Redistrubute element boxes among children
6338    */
6339   //================================================================================
6340
6341   void ElementBndBoxTree::buildChildrenData()
6342   {
6343     for ( int i = 0; i < _elements.size(); ++i )
6344     {
6345       for (int j = 0; j < 8; j++)
6346       {
6347         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6348         {
6349           _elements[i]->_refCount++;
6350           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6351         }
6352       }
6353       _elements[i]->_refCount--;
6354     }
6355     _elements.clear();
6356
6357     for (int j = 0; j < 8; j++)
6358     {
6359       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6360       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6361         child->myIsLeaf = true;
6362
6363       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6364         child->_elements.resize( child->_elements.size() ); // compact
6365     }
6366   }
6367
6368   //================================================================================
6369   /*!
6370    * \brief Return elements which can include the point
6371    */
6372   //================================================================================
6373
6374   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6375                                                 TIDSortedElemSet& foundElems)
6376   {
6377     if ( level() && getBox().IsOut( point.XYZ() ))
6378       return;
6379
6380     if ( isLeaf() )
6381     {
6382       for ( int i = 0; i < _elements.size(); ++i )
6383         if ( !_elements[i]->IsOut( point.XYZ() ))
6384           foundElems.insert( _elements[i]->_element );
6385     }
6386     else
6387     {
6388       for (int i = 0; i < 8; i++)
6389         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6390     }
6391   }
6392
6393   //================================================================================
6394   /*!
6395    * \brief Return elements which can be intersected by the line
6396    */
6397   //================================================================================
6398
6399   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6400                                                TIDSortedElemSet& foundElems)
6401   {
6402     if ( level() && getBox().IsOut( line ))
6403       return;
6404
6405     if ( isLeaf() )
6406     {
6407       for ( int i = 0; i < _elements.size(); ++i )
6408         if ( !_elements[i]->IsOut( line ))
6409           foundElems.insert( _elements[i]->_element );
6410     }
6411     else
6412     {
6413       for (int i = 0; i < 8; i++)
6414         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6415     }
6416   }
6417
6418   //================================================================================
6419   /*!
6420    * \brief Construct the element box
6421    */
6422   //================================================================================
6423
6424   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6425   {
6426     _element  = elem;
6427     _refCount = 1;
6428     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6429     while ( nIt->more() )
6430       Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6431     Enlarge( tolerance );
6432   }
6433
6434 } // namespace
6435
6436 //=======================================================================
6437 /*!
6438  * \brief Implementation of search for the elements by point and
6439  *        of classification of point in 2D mesh
6440  */
6441 //=======================================================================
6442
6443 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6444 {
6445   SMESHDS_Mesh*                _mesh;
6446   ElementBndBoxTree*           _ebbTree;
6447   SMESH_NodeSearcherImpl*      _nodeSearcher;
6448   SMDSAbs_ElementType          _elementType;
6449   double                       _tolerance;
6450   bool                         _outerFacesFound;
6451   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6452
6453   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6454     : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6455   ~SMESH_ElementSearcherImpl()
6456   {
6457     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6458     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6459   }
6460   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6461                                   SMDSAbs_ElementType                type,
6462                                   vector< const SMDS_MeshElement* >& foundElements);
6463   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6464
6465   void GetElementsNearLine( const gp_Ax1&                      line,
6466                             SMDSAbs_ElementType                type,
6467                             vector< const SMDS_MeshElement* >& foundElems);
6468   double getTolerance();
6469   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6470                             const double tolerance, double & param);
6471   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6472   bool isOuterBoundary(const SMDS_MeshElement* face) const
6473   {
6474     return _outerFaces.empty() || _outerFaces.count(face);
6475   }
6476   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6477   {
6478     const SMDS_MeshElement* _face;
6479     gp_Vec                  _faceNorm;
6480     bool                    _coincides; //!< the line lays in face plane
6481     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6482       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6483   };
6484   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6485   {
6486     SMESH_TLink      _link;
6487     TIDSortedElemSet _faces;
6488     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6489       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6490   };
6491 };
6492
6493 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6494 {
6495   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6496              << ", _coincides="<<i._coincides << ")";
6497 }
6498
6499 //=======================================================================
6500 /*!
6501  * \brief define tolerance for search
6502  */
6503 //=======================================================================
6504
6505 double SMESH_ElementSearcherImpl::getTolerance()
6506 {
6507   if ( _tolerance < 0 )
6508   {
6509     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6510
6511     _tolerance = 0;
6512     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6513     {
6514       double boxSize = _nodeSearcher->getTree()->maxSize();
6515       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6516     }
6517     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6518     {
6519       double boxSize = _ebbTree->maxSize();
6520       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6521     }
6522     if ( _tolerance == 0 )
6523     {
6524       // define tolerance by size of a most complex element
6525       int complexType = SMDSAbs_Volume;
6526       while ( complexType > SMDSAbs_All &&
6527               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6528         --complexType;
6529       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6530       double elemSize;
6531       if ( complexType == int( SMDSAbs_Node ))
6532       {
6533         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6534         elemSize = 1;
6535         if ( meshInfo.NbNodes() > 2 )
6536           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6537       }
6538       else
6539       {
6540         SMDS_ElemIteratorPtr elemIt =
6541             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6542         const SMDS_MeshElement* elem = elemIt->next();
6543         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6544         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6545         while ( nodeIt->more() )
6546         {
6547           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6548           elemSize = max( dist, elemSize );
6549         }
6550       }
6551       _tolerance = 1e-4 * elemSize;
6552     }
6553   }
6554   return _tolerance;
6555 }
6556
6557 //================================================================================
6558 /*!
6559  * \brief Find intersection of the line and an edge of face and return parameter on line
6560  */
6561 //================================================================================
6562
6563 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6564                                                      const SMDS_MeshElement* face,
6565                                                      const double            tol,
6566                                                      double &                param)
6567 {
6568   int nbInts = 0;
6569   param = 0;
6570
6571   GeomAPI_ExtremaCurveCurve anExtCC;
6572   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6573   
6574   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6575   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6576   {
6577     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6578                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6579     anExtCC.Init( lineCurve, edge);
6580     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6581     {
6582       Quantity_Parameter pl, pe;
6583       anExtCC.LowerDistanceParameters( pl, pe );
6584       param += pl;
6585       if ( ++nbInts == 2 )
6586         break;
6587     }
6588   }
6589   if ( nbInts > 0 ) param /= nbInts;
6590   return nbInts > 0;
6591 }
6592 //================================================================================
6593 /*!
6594  * \brief Find all faces belonging to the outer boundary of mesh
6595  */
6596 //================================================================================
6597
6598 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6599 {
6600   if ( _outerFacesFound ) return;
6601
6602   // Collect all outer faces by passing from one outer face to another via their links
6603   // and BTW find out if there are internal faces at all.
6604
6605   // checked links and links where outer boundary meets internal one
6606   set< SMESH_TLink > visitedLinks, seamLinks;
6607
6608   // links to treat with already visited faces sharing them
6609   list < TFaceLink > startLinks;
6610
6611   // load startLinks with the first outerFace
6612   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6613   _outerFaces.insert( outerFace );
6614
6615   TIDSortedElemSet emptySet;
6616   while ( !startLinks.empty() )
6617   {
6618     const SMESH_TLink& link  = startLinks.front()._link;
6619     TIDSortedElemSet&  faces = startLinks.front()._faces;
6620
6621     outerFace = *faces.begin();
6622     // find other faces sharing the link
6623     const SMDS_MeshElement* f;
6624     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6625       faces.insert( f );
6626
6627     // select another outer face among the found 
6628     const SMDS_MeshElement* outerFace2 = 0;
6629     if ( faces.size() == 2 )
6630     {
6631       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6632     }
6633     else if ( faces.size() > 2 )
6634     {
6635       seamLinks.insert( link );
6636
6637       // link direction within the outerFace
6638       gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6639                    SMESH_MeshEditor::TNodeXYZ( link.node2()));
6640       int i1 = outerFace->GetNodeIndex( link.node1() );
6641       int i2 = outerFace->GetNodeIndex( link.node2() );
6642       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6643       if ( rev ) n1n2.Reverse();
6644       // outerFace normal
6645       gp_XYZ ofNorm, fNorm;
6646       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6647       {
6648         // direction from the link inside outerFace
6649         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6650         // sort all other faces by angle with the dirInOF
6651         map< double, const SMDS_MeshElement* > angle2Face;
6652         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6653         for ( ; face != faces.end(); ++face )
6654         {
6655           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6656             continue;
6657           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6658           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6659           if ( angle < 0 ) angle += 2*PI;
6660           angle2Face.insert( make_pair( angle, *face ));
6661         }
6662         if ( !angle2Face.empty() )
6663           outerFace2 = angle2Face.begin()->second;
6664       }
6665     }
6666     // store the found outer face and add its links to continue seaching from
6667     if ( outerFace2 )
6668     {
6669       _outerFaces.insert( outerFace );
6670       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6671       for ( int i = 0; i < nbNodes; ++i )
6672       {
6673         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6674         if ( visitedLinks.insert( link2 ).second )
6675           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6676       }
6677     }
6678     startLinks.pop_front();
6679   }
6680   _outerFacesFound = true;
6681
6682   if ( !seamLinks.empty() )
6683   {
6684     // There are internal boundaries touching the outher one,
6685     // find all faces of internal boundaries in order to find
6686     // faces of boundaries of holes, if any.
6687     
6688   }
6689   else
6690   {
6691     _outerFaces.clear();
6692   }
6693 }
6694
6695 //=======================================================================
6696 /*!
6697  * \brief Find elements of given type where the given point is IN or ON.
6698  *        Returns nb of found elements and elements them-selves.
6699  *
6700  * 'ALL' type means elements of any type excluding nodes and 0D elements
6701  */
6702 //=======================================================================
6703
6704 int SMESH_ElementSearcherImpl::
6705 FindElementsByPoint(const gp_Pnt&                      point,
6706                     SMDSAbs_ElementType                type,
6707                     vector< const SMDS_MeshElement* >& foundElements)
6708 {
6709   foundElements.clear();
6710
6711   double tolerance = getTolerance();
6712
6713   // =================================================================================
6714   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6715   {
6716     if ( !_nodeSearcher )
6717       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6718
6719     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6720     if ( !closeNode ) return foundElements.size();
6721
6722     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6723       return foundElements.size(); // to far from any node
6724
6725     if ( type == SMDSAbs_Node )
6726     {
6727       foundElements.push_back( closeNode );
6728     }
6729     else
6730     {
6731       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6732       while ( elemIt->more() )
6733         foundElements.push_back( elemIt->next() );
6734     }
6735   }
6736   // =================================================================================
6737   else // elements more complex than 0D
6738   {
6739     if ( !_ebbTree || _elementType != type )
6740     {
6741       if ( _ebbTree ) delete _ebbTree;
6742       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance );
6743     }
6744     TIDSortedElemSet suspectElems;
6745     _ebbTree->getElementsNearPoint( point, suspectElems );
6746     TIDSortedElemSet::iterator elem = suspectElems.begin();
6747     for ( ; elem != suspectElems.end(); ++elem )
6748       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6749         foundElements.push_back( *elem );
6750   }
6751   return foundElements.size();
6752 }
6753
6754 //================================================================================
6755 /*!
6756  * \brief Classify the given point in the closed 2D mesh
6757  */
6758 //================================================================================
6759
6760 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6761 {
6762   double tolerance = getTolerance();
6763   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6764   {
6765     if ( _ebbTree ) delete _ebbTree;
6766     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6767   }
6768   // Algo: analyse transition of a line starting at the point through mesh boundary;
6769   // try three lines parallel to axis of the coordinate system and perform rough
6770   // analysis. If solution is not clear perform thorough analysis.
6771
6772   const int nbAxes = 3;
6773   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6774   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6775   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6776   multimap< int, int > nbInt2Axis; // to find the simplest case
6777   for ( int axis = 0; axis < nbAxes; ++axis )
6778   {
6779     gp_Ax1 lineAxis( point, axisDir[axis]);
6780     gp_Lin line    ( lineAxis );
6781
6782     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6783     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6784
6785     // Intersect faces with the line
6786
6787     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6788     TIDSortedElemSet::iterator face = suspectFaces.begin();
6789     for ( ; face != suspectFaces.end(); ++face )
6790     {
6791       // get face plane
6792       gp_XYZ fNorm;
6793       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6794       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6795
6796       // perform intersection
6797       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6798       if ( !intersection.IsDone() )
6799         continue;
6800       if ( intersection.IsInQuadric() )
6801       {
6802         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6803       }
6804       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6805       {
6806         gp_Pnt intersectionPoint = intersection.Point(1);
6807         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6808           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6809       }
6810     }
6811     // Analyse intersections roughly
6812
6813     int nbInter = u2inters.size();
6814     if ( nbInter == 0 )
6815       return TopAbs_OUT; 
6816
6817     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6818     if ( nbInter == 1 ) // not closed mesh
6819       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6820
6821     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6822       return TopAbs_ON;
6823
6824     if ( (f<0) == (l<0) )
6825       return TopAbs_OUT;
6826
6827     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6828     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6829     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6830       return TopAbs_IN;
6831
6832     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6833
6834     if ( _outerFacesFound ) break; // pass to thorough analysis
6835
6836   } // three attempts - loop on CS axes
6837
6838   // Analyse intersections thoroughly.
6839   // We make two loops maximum, on the first one we only exclude touching intersections,
6840   // on the second, if situation is still unclear, we gather and use information on
6841   // position of faces (internal or outer). If faces position is already gathered,
6842   // we make the second loop right away.
6843
6844   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6845   {
6846     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6847     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6848     {
6849       int axis = nb_axis->second;
6850       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6851
6852       gp_Ax1 lineAxis( point, axisDir[axis]);
6853       gp_Lin line    ( lineAxis );
6854
6855       // add tangent intersections to u2inters
6856       double param;
6857       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6858       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6859         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6860           u2inters.insert(make_pair( param, *tgtInt ));
6861       tangentInters[ axis ].clear();
6862
6863       // Count intersections before and after the point excluding touching ones.
6864       // If hasPositionInfo we count intersections of outer boundary only
6865
6866       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6867       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6868       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6869       bool ok = ! u_int1->second._coincides;
6870       while ( ok && u_int1 != u2inters.end() )
6871       {
6872         double u = u_int1->first;
6873         bool touchingInt = false;
6874         if ( ++u_int2 != u2inters.end() )
6875         {
6876           // skip intersections at the same point (if the line passes through edge or node)
6877           int nbSamePnt = 0;
6878           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6879           {
6880             ++nbSamePnt;
6881             ++u_int2;
6882           }
6883
6884           // skip tangent intersections
6885           int nbTgt = 0;
6886           const SMDS_MeshElement* prevFace = u_int1->second._face;
6887           while ( ok && u_int2->second._coincides )
6888           {
6889             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6890               ok = false;
6891             else
6892             {
6893               nbTgt++;
6894               u_int2++;
6895               ok = ( u_int2 != u2inters.end() );
6896             }
6897           }
6898           if ( !ok ) break;
6899
6900           // skip intersections at the same point after tangent intersections
6901           if ( nbTgt > 0 )
6902           {
6903             double u2 = u_int2->first;
6904             ++u_int2;
6905             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6906             {
6907               ++nbSamePnt;
6908               ++u_int2;
6909             }
6910           }
6911           // decide if we skipped a touching intersection
6912           if ( nbSamePnt + nbTgt > 0 )
6913           {
6914             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6915             map< double, TInters >::iterator u_int = u_int1;
6916             for ( ; u_int != u_int2; ++u_int )
6917             {
6918               if ( u_int->second._coincides ) continue;
6919               double dot = u_int->second._faceNorm * line.Direction();
6920               if ( dot > maxDot ) maxDot = dot;
6921               if ( dot < minDot ) minDot = dot;
6922             }
6923             touchingInt = ( minDot*maxDot < 0 );
6924           }
6925         }
6926         if ( !touchingInt )
6927         {
6928           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6929           {
6930             if ( u < 0 )
6931               ++nbIntBeforePoint;
6932             else
6933               ++nbIntAfterPoint;
6934           }
6935           if ( u < f ) f = u;
6936           if ( u > l ) l = u;
6937         }
6938
6939         u_int1 = u_int2; // to next intersection
6940
6941       } // loop on intersections with one line
6942
6943       if ( ok )
6944       {
6945         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6946           return TopAbs_ON;
6947
6948         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6949           return TopAbs_OUT; 
6950
6951         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6952           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6953
6954         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6955           return TopAbs_IN;
6956
6957         if ( (f<0) == (l<0) )
6958           return TopAbs_OUT;
6959
6960         if ( hasPositionInfo )
6961           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6962       }
6963     } // loop on intersections of the tree lines - thorough analysis
6964
6965     if ( !hasPositionInfo )
6966     {
6967       // gather info on faces position - is face in the outer boundary or not
6968       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6969       findOuterBoundary( u2inters.begin()->second._face );
6970     }
6971
6972   } // two attempts - with and w/o faces position info in the mesh
6973
6974   return TopAbs_UNKNOWN;
6975 }
6976
6977 //=======================================================================
6978 /*!
6979  * \brief Return elements possibly intersecting the line
6980  */
6981 //=======================================================================
6982
6983 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
6984                                                      SMDSAbs_ElementType                type,
6985                                                      vector< const SMDS_MeshElement* >& foundElems)
6986 {
6987   if ( !_ebbTree || _elementType != type )
6988   {
6989     if ( _ebbTree ) delete _ebbTree;
6990     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6991   }
6992   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
6993   _ebbTree->getElementsNearLine( line, suspectFaces );
6994   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
6995 }
6996
6997 //=======================================================================
6998 /*!
6999  * \brief Return SMESH_ElementSearcher
7000  */
7001 //=======================================================================
7002
7003 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7004 {
7005   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7006 }
7007
7008 //=======================================================================
7009 /*!
7010  * \brief Return true if the point is IN or ON of the element
7011  */
7012 //=======================================================================
7013
7014 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7015 {
7016   if ( element->GetType() == SMDSAbs_Volume)
7017   {
7018     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7019   }
7020
7021   // get ordered nodes
7022
7023   vector< gp_XYZ > xyz;
7024   vector<const SMDS_MeshNode*> nodeList;
7025
7026   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7027   if ( element->IsQuadratic() )
7028     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7029       nodeIt = f->interlacedNodesElemIterator();
7030     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7031       nodeIt = e->interlacedNodesElemIterator();
7032
7033   while ( nodeIt->more() )
7034     {
7035       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7036       xyz.push_back( TNodeXYZ(node) );
7037       nodeList.push_back(node);
7038     }
7039
7040   int i, nbNodes = element->NbNodes();
7041
7042   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7043   {
7044     // compute face normal
7045     gp_Vec faceNorm(0,0,0);
7046     xyz.push_back( xyz.front() );
7047     nodeList.push_back( nodeList.front() );
7048     for ( i = 0; i < nbNodes; ++i )
7049     {
7050       gp_Vec edge1( xyz[i+1], xyz[i]);
7051       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7052       faceNorm += edge1 ^ edge2;
7053     }
7054     double normSize = faceNorm.Magnitude();
7055     if ( normSize <= tol )
7056     {
7057       // degenerated face: point is out if it is out of all face edges
7058       for ( i = 0; i < nbNodes; ++i )
7059       {
7060         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7061         if ( !isOut( &edge, point, tol ))
7062           return false;
7063       }
7064       return true;
7065     }
7066     faceNorm /= normSize;
7067
7068     // check if the point lays on face plane
7069     gp_Vec n2p( xyz[0], point );
7070     if ( fabs( n2p * faceNorm ) > tol )
7071       return true; // not on face plane
7072
7073     // check if point is out of face boundary:
7074     // define it by closest transition of a ray point->infinity through face boundary
7075     // on the face plane.
7076     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7077     // to find intersections of the ray with the boundary.
7078     gp_Vec ray = n2p;
7079     gp_Vec plnNorm = ray ^ faceNorm;
7080     normSize = plnNorm.Magnitude();
7081     if ( normSize <= tol ) return false; // point coincides with the first node
7082     plnNorm /= normSize;
7083     // for each node of the face, compute its signed distance to the plane
7084     vector<double> dist( nbNodes + 1);
7085     for ( i = 0; i < nbNodes; ++i )
7086     {
7087       gp_Vec n2p( xyz[i], point );
7088       dist[i] = n2p * plnNorm;
7089     }
7090     dist.back() = dist.front();
7091     // find the closest intersection
7092     int    iClosest = -1;
7093     double rClosest, distClosest = 1e100;;
7094     gp_Pnt pClosest;
7095     for ( i = 0; i < nbNodes; ++i )
7096     {
7097       double r;
7098       if ( fabs( dist[i]) < tol )
7099         r = 0.;
7100       else if ( fabs( dist[i+1]) < tol )
7101         r = 1.;
7102       else if ( dist[i] * dist[i+1] < 0 )
7103         r = dist[i] / ( dist[i] - dist[i+1] );
7104       else
7105         continue; // no intersection
7106       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7107       gp_Vec p2int ( point, pInt);
7108       if ( p2int * ray > -tol ) // right half-space
7109       {
7110         double intDist = p2int.SquareMagnitude();
7111         if ( intDist < distClosest )
7112         {
7113           iClosest = i;
7114           rClosest = r;
7115           pClosest = pInt;
7116           distClosest = intDist;
7117         }
7118       }
7119     }
7120     if ( iClosest < 0 )
7121       return true; // no intesections - out
7122
7123     // analyse transition
7124     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7125     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7126     gp_Vec p2int ( point, pClosest );
7127     bool out = (edgeNorm * p2int) < -tol;
7128     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7129       return out;
7130
7131     // ray pass through a face node; analyze transition through an adjacent edge
7132     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7133     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7134     gp_Vec edgeAdjacent( p1, p2 );
7135     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7136     bool out2 = (edgeNorm2 * p2int) < -tol;
7137
7138     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7139     return covexCorner ? (out || out2) : (out && out2);
7140   }
7141   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7142   {
7143     // point is out of edge if it is NOT ON any straight part of edge
7144     // (we consider quadratic edge as being composed of two straight parts)
7145     for ( i = 1; i < nbNodes; ++i )
7146     {
7147       gp_Vec edge( xyz[i-1], xyz[i]);
7148       gp_Vec n1p ( xyz[i-1], point);
7149       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7150       if ( dist > tol )
7151         continue;
7152       gp_Vec n2p( xyz[i], point );
7153       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7154         continue;
7155       return false; // point is ON this part
7156     }
7157     return true;
7158   }
7159   // Node or 0D element -------------------------------------------------------------------------
7160   {
7161     gp_Vec n2p ( xyz[0], point );
7162     return n2p.Magnitude() <= tol;
7163   }
7164   return true;
7165 }
7166
7167 //=======================================================================
7168 //function : SimplifyFace
7169 //purpose  :
7170 //=======================================================================
7171 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7172                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7173                                     vector<int>&                        quantities) const
7174 {
7175   int nbNodes = faceNodes.size();
7176
7177   if (nbNodes < 3)
7178     return 0;
7179
7180   set<const SMDS_MeshNode*> nodeSet;
7181
7182   // get simple seq of nodes
7183   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7184   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7185   int iSimple = 0, nbUnique = 0;
7186
7187   simpleNodes[iSimple++] = faceNodes[0];
7188   nbUnique++;
7189   for (int iCur = 1; iCur < nbNodes; iCur++) {
7190     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7191       simpleNodes[iSimple++] = faceNodes[iCur];
7192       if (nodeSet.insert( faceNodes[iCur] ).second)
7193         nbUnique++;
7194     }
7195   }
7196   int nbSimple = iSimple;
7197   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7198     nbSimple--;
7199     iSimple--;
7200   }
7201
7202   if (nbUnique < 3)
7203     return 0;
7204
7205   // separate loops
7206   int nbNew = 0;
7207   bool foundLoop = (nbSimple > nbUnique);
7208   while (foundLoop) {
7209     foundLoop = false;
7210     set<const SMDS_MeshNode*> loopSet;
7211     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7212       const SMDS_MeshNode* n = simpleNodes[iSimple];
7213       if (!loopSet.insert( n ).second) {
7214         foundLoop = true;
7215
7216         // separate loop
7217         int iC = 0, curLast = iSimple;
7218         for (; iC < curLast; iC++) {
7219           if (simpleNodes[iC] == n) break;
7220         }
7221         int loopLen = curLast - iC;
7222         if (loopLen > 2) {
7223           // create sub-element
7224           nbNew++;
7225           quantities.push_back(loopLen);
7226           for (; iC < curLast; iC++) {
7227             poly_nodes.push_back(simpleNodes[iC]);
7228           }
7229         }
7230         // shift the rest nodes (place from the first loop position)
7231         for (iC = curLast + 1; iC < nbSimple; iC++) {
7232           simpleNodes[iC - loopLen] = simpleNodes[iC];
7233         }
7234         nbSimple -= loopLen;
7235         iSimple -= loopLen;
7236       }
7237     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7238   } // while (foundLoop)
7239
7240   if (iSimple > 2) {
7241     nbNew++;
7242     quantities.push_back(iSimple);
7243     for (int i = 0; i < iSimple; i++)
7244       poly_nodes.push_back(simpleNodes[i]);
7245   }
7246
7247   return nbNew;
7248 }
7249
7250 //=======================================================================
7251 //function : MergeNodes
7252 //purpose  : In each group, the cdr of nodes are substituted by the first one
7253 //           in all elements.
7254 //=======================================================================
7255
7256 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7257 {
7258   MESSAGE("MergeNodes");
7259   myLastCreatedElems.Clear();
7260   myLastCreatedNodes.Clear();
7261
7262   SMESHDS_Mesh* aMesh = GetMeshDS();
7263
7264   TNodeNodeMap nodeNodeMap; // node to replace - new node
7265   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7266   list< int > rmElemIds, rmNodeIds;
7267
7268   // Fill nodeNodeMap and elems
7269
7270   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7271   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7272     list<const SMDS_MeshNode*>& nodes = *grIt;
7273     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7274     const SMDS_MeshNode* nToKeep = *nIt;
7275     //MESSAGE("node to keep " << nToKeep->GetID());
7276     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7277       const SMDS_MeshNode* nToRemove = *nIt;
7278       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7279       if ( nToRemove != nToKeep ) {
7280         //MESSAGE("  node to remove " << nToRemove->GetID());
7281         rmNodeIds.push_back( nToRemove->GetID() );
7282         AddToSameGroups( nToKeep, nToRemove, aMesh );
7283       }
7284
7285       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7286       while ( invElemIt->more() ) {
7287         const SMDS_MeshElement* elem = invElemIt->next();
7288         elems.insert(elem);
7289       }
7290     }
7291   }
7292   // Change element nodes or remove an element
7293
7294   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7295   for ( ; eIt != elems.end(); eIt++ ) {
7296     const SMDS_MeshElement* elem = *eIt;
7297     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7298     int nbNodes = elem->NbNodes();
7299     int aShapeId = FindShape( elem );
7300
7301     set<const SMDS_MeshNode*> nodeSet;
7302     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7303     int iUnique = 0, iCur = 0, nbRepl = 0;
7304     vector<int> iRepl( nbNodes );
7305
7306     // get new seq of nodes
7307     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7308     while ( itN->more() ) {
7309       const SMDS_MeshNode* n =
7310         static_cast<const SMDS_MeshNode*>( itN->next() );
7311
7312       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7313       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7314         n = (*nnIt).second;
7315         // BUG 0020185: begin
7316         {
7317           bool stopRecur = false;
7318           set<const SMDS_MeshNode*> nodesRecur;
7319           nodesRecur.insert(n);
7320           while (!stopRecur) {
7321             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7322             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7323               n = (*nnIt_i).second;
7324               if (!nodesRecur.insert(n).second) {
7325                 // error: recursive dependancy
7326                 stopRecur = true;
7327               }
7328             }
7329             else
7330               stopRecur = true;
7331           }
7332         }
7333         // BUG 0020185: end
7334         iRepl[ nbRepl++ ] = iCur;
7335       }
7336       curNodes[ iCur ] = n;
7337       bool isUnique = nodeSet.insert( n ).second;
7338       if ( isUnique )
7339         uniqueNodes[ iUnique++ ] = n;
7340       iCur++;
7341     }
7342
7343     // Analyse element topology after replacement
7344
7345     bool isOk = true;
7346     int nbUniqueNodes = nodeSet.size();
7347     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7348     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7349       // Polygons and Polyhedral volumes
7350       if (elem->IsPoly()) {
7351
7352         if (elem->GetType() == SMDSAbs_Face) {
7353           // Polygon
7354           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7355           int inode = 0;
7356           for (; inode < nbNodes; inode++) {
7357             face_nodes[inode] = curNodes[inode];
7358           }
7359
7360           vector<const SMDS_MeshNode *> polygons_nodes;
7361           vector<int> quantities;
7362           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7363
7364           if (nbNew > 0) {
7365             inode = 0;
7366             for (int iface = 0; iface < nbNew - 1; iface++) {
7367               int nbNodes = quantities[iface];
7368               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7369               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7370                 poly_nodes[ii] = polygons_nodes[inode];
7371               }
7372               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7373               myLastCreatedElems.Append(newElem);
7374               if (aShapeId)
7375                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7376             }
7377
7378             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7379             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7380             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7381             int quid =0;
7382             if (nbNew > 0) quid = nbNew - 1;
7383             vector<int> newquant(quantities.begin()+quid, quantities.end());
7384             const SMDS_MeshElement* newElem = 0;
7385             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7386             myLastCreatedElems.Append(newElem);
7387             if ( aShapeId && newElem )
7388               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7389             rmElemIds.push_back(elem->GetID());
7390           }
7391           else {
7392             rmElemIds.push_back(elem->GetID());
7393           }
7394
7395         }
7396         else if (elem->GetType() == SMDSAbs_Volume) {
7397           // Polyhedral volume
7398           if (nbUniqueNodes < 4) {
7399             rmElemIds.push_back(elem->GetID());
7400           }
7401           else {
7402             // each face has to be analyzed in order to check volume validity
7403             const SMDS_VtkVolume* aPolyedre =
7404               dynamic_cast<const SMDS_VtkVolume*>( elem );
7405             if (aPolyedre) {
7406               int nbFaces = aPolyedre->NbFaces();
7407
7408               vector<const SMDS_MeshNode *> poly_nodes;
7409               vector<int> quantities;
7410
7411               for (int iface = 1; iface <= nbFaces; iface++) {
7412                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7413                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7414
7415                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7416                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7417                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7418                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7419                     faceNode = (*nnIt).second;
7420                   }
7421                   faceNodes[inode - 1] = faceNode;
7422                 }
7423
7424                 SimplifyFace(faceNodes, poly_nodes, quantities);
7425               }
7426
7427               if (quantities.size() > 3) {
7428                 // to be done: remove coincident faces
7429               }
7430
7431               if (quantities.size() > 3)
7432                 {
7433                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7434                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7435                   const SMDS_MeshElement* newElem = 0;
7436                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7437                   myLastCreatedElems.Append(newElem);
7438                   if ( aShapeId && newElem )
7439                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7440                   rmElemIds.push_back(elem->GetID());
7441                 }
7442             }
7443             else {
7444               rmElemIds.push_back(elem->GetID());
7445             }
7446           }
7447         }
7448         else {
7449         }
7450
7451         continue;
7452       }
7453
7454       // Regular elements
7455       // TODO not all the possible cases are solved. Find something more generic?
7456       switch ( nbNodes ) {
7457       case 2: ///////////////////////////////////// EDGE
7458         isOk = false; break;
7459       case 3: ///////////////////////////////////// TRIANGLE
7460         isOk = false; break;
7461       case 4:
7462         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7463           isOk = false;
7464         else { //////////////////////////////////// QUADRANGLE
7465           if ( nbUniqueNodes < 3 )
7466             isOk = false;
7467           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7468             isOk = false; // opposite nodes stick
7469           //MESSAGE("isOk " << isOk);
7470         }
7471         break;
7472       case 6: ///////////////////////////////////// PENTAHEDRON
7473         if ( nbUniqueNodes == 4 ) {
7474           // ---------------------------------> tetrahedron
7475           if (nbRepl == 3 &&
7476               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7477             // all top nodes stick: reverse a bottom
7478             uniqueNodes[ 0 ] = curNodes [ 1 ];
7479             uniqueNodes[ 1 ] = curNodes [ 0 ];
7480           }
7481           else if (nbRepl == 3 &&
7482                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7483             // all bottom nodes stick: set a top before
7484             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7485             uniqueNodes[ 0 ] = curNodes [ 3 ];
7486             uniqueNodes[ 1 ] = curNodes [ 4 ];
7487             uniqueNodes[ 2 ] = curNodes [ 5 ];
7488           }
7489           else if (nbRepl == 4 &&
7490                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7491             // a lateral face turns into a line: reverse a bottom
7492             uniqueNodes[ 0 ] = curNodes [ 1 ];
7493             uniqueNodes[ 1 ] = curNodes [ 0 ];
7494           }
7495           else
7496             isOk = false;
7497         }
7498         else if ( nbUniqueNodes == 5 ) {
7499           // PENTAHEDRON --------------------> 2 tetrahedrons
7500           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7501             // a bottom node sticks with a linked top one
7502             // 1.
7503             SMDS_MeshElement* newElem =
7504               aMesh->AddVolume(curNodes[ 3 ],
7505                                curNodes[ 4 ],
7506                                curNodes[ 5 ],
7507                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7508             myLastCreatedElems.Append(newElem);
7509             if ( aShapeId )
7510               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7511             // 2. : reverse a bottom
7512             uniqueNodes[ 0 ] = curNodes [ 1 ];
7513             uniqueNodes[ 1 ] = curNodes [ 0 ];
7514             nbUniqueNodes = 4;
7515           }
7516           else
7517             isOk = false;
7518         }
7519         else
7520           isOk = false;
7521         break;
7522       case 8: {
7523         if(elem->IsQuadratic()) { // Quadratic quadrangle
7524           //   1    5    2
7525           //    +---+---+
7526           //    |       |
7527           //    |       |
7528           //   4+       +6
7529           //    |       |
7530           //    |       |
7531           //    +---+---+
7532           //   0    7    3
7533           isOk = false;
7534           if(nbRepl==2) {
7535             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7536           }
7537           if(nbRepl==3) {
7538             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7539             nbUniqueNodes = 6;
7540             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7541               uniqueNodes[0] = curNodes[0];
7542               uniqueNodes[1] = curNodes[2];
7543               uniqueNodes[2] = curNodes[3];
7544               uniqueNodes[3] = curNodes[5];
7545               uniqueNodes[4] = curNodes[6];
7546               uniqueNodes[5] = curNodes[7];
7547               isOk = true;
7548             }
7549             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7550               uniqueNodes[0] = curNodes[0];
7551               uniqueNodes[1] = curNodes[1];
7552               uniqueNodes[2] = curNodes[2];
7553               uniqueNodes[3] = curNodes[4];
7554               uniqueNodes[4] = curNodes[5];
7555               uniqueNodes[5] = curNodes[6];
7556               isOk = true;
7557             }
7558             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7559               uniqueNodes[0] = curNodes[1];
7560               uniqueNodes[1] = curNodes[2];
7561               uniqueNodes[2] = curNodes[3];
7562               uniqueNodes[3] = curNodes[5];
7563               uniqueNodes[4] = curNodes[6];
7564               uniqueNodes[5] = curNodes[0];
7565               isOk = true;
7566             }
7567             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7568               uniqueNodes[0] = curNodes[0];
7569               uniqueNodes[1] = curNodes[1];
7570               uniqueNodes[2] = curNodes[3];
7571               uniqueNodes[3] = curNodes[4];
7572               uniqueNodes[4] = curNodes[6];
7573               uniqueNodes[5] = curNodes[7];
7574               isOk = true;
7575             }
7576             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7577               uniqueNodes[0] = curNodes[0];
7578               uniqueNodes[1] = curNodes[2];
7579               uniqueNodes[2] = curNodes[3];
7580               uniqueNodes[3] = curNodes[1];
7581               uniqueNodes[4] = curNodes[6];
7582               uniqueNodes[5] = curNodes[7];
7583               isOk = true;
7584             }
7585             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7586               uniqueNodes[0] = curNodes[0];
7587               uniqueNodes[1] = curNodes[1];
7588               uniqueNodes[2] = curNodes[2];
7589               uniqueNodes[3] = curNodes[4];
7590               uniqueNodes[4] = curNodes[5];
7591               uniqueNodes[5] = curNodes[7];
7592               isOk = true;
7593             }
7594             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7595               uniqueNodes[0] = curNodes[0];
7596               uniqueNodes[1] = curNodes[1];
7597               uniqueNodes[2] = curNodes[3];
7598               uniqueNodes[3] = curNodes[4];
7599               uniqueNodes[4] = curNodes[2];
7600               uniqueNodes[5] = curNodes[7];
7601               isOk = true;
7602             }
7603             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7604               uniqueNodes[0] = curNodes[0];
7605               uniqueNodes[1] = curNodes[1];
7606               uniqueNodes[2] = curNodes[2];
7607               uniqueNodes[3] = curNodes[4];
7608               uniqueNodes[4] = curNodes[5];
7609               uniqueNodes[5] = curNodes[3];
7610               isOk = true;
7611             }
7612           }
7613           if(nbRepl==4) {
7614             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7615           }
7616           if(nbRepl==5) {
7617             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7618           }
7619           break;
7620         }
7621         //////////////////////////////////// HEXAHEDRON
7622         isOk = false;
7623         SMDS_VolumeTool hexa (elem);
7624         hexa.SetExternalNormal();
7625         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7626           //////////////////////// ---> tetrahedron
7627           for ( int iFace = 0; iFace < 6; iFace++ ) {
7628             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7629             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7630                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7631                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7632               // one face turns into a point ...
7633               int iOppFace = hexa.GetOppFaceIndex( iFace );
7634               ind = hexa.GetFaceNodesIndices( iOppFace );
7635               int nbStick = 0;
7636               iUnique = 2; // reverse a tetrahedron bottom
7637               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7638                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7639                   nbStick++;
7640                 else if ( iUnique >= 0 )
7641                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7642               }
7643               if ( nbStick == 1 ) {
7644                 // ... and the opposite one - into a triangle.
7645                 // set a top node
7646                 ind = hexa.GetFaceNodesIndices( iFace );
7647                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7648                 isOk = true;
7649               }
7650               break;
7651             }
7652           }
7653         }
7654         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7655           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7656           for ( int iFace = 0; iFace < 6; iFace++ ) {
7657             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7658             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7659                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7660                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7661               // one face turns into a point ...
7662               int iOppFace = hexa.GetOppFaceIndex( iFace );
7663               ind = hexa.GetFaceNodesIndices( iOppFace );
7664               int nbStick = 0;
7665               iUnique = 2;  // reverse a tetrahedron 1 bottom
7666               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7667                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7668                   nbStick++;
7669                 else if ( iUnique >= 0 )
7670                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7671               }
7672               if ( nbStick == 0 ) {
7673                 // ... and the opposite one is a quadrangle
7674                 // set a top node
7675                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7676                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7677                 nbUniqueNodes = 4;
7678                 // tetrahedron 2
7679                 SMDS_MeshElement* newElem =
7680                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7681                                    curNodes[ind[ 3 ]],
7682                                    curNodes[ind[ 2 ]],
7683                                    curNodes[indTop[ 0 ]]);
7684                 myLastCreatedElems.Append(newElem);
7685                 if ( aShapeId )
7686                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7687                 isOk = true;
7688               }
7689               break;
7690             }
7691           }
7692         }
7693         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7694           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7695           // find indices of quad and tri faces
7696           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7697           for ( iFace = 0; iFace < 6; iFace++ ) {
7698             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7699             nodeSet.clear();
7700             for ( iCur = 0; iCur < 4; iCur++ )
7701               nodeSet.insert( curNodes[ind[ iCur ]] );
7702             nbUniqueNodes = nodeSet.size();
7703             if ( nbUniqueNodes == 3 )
7704               iTriFace[ nbTri++ ] = iFace;
7705             else if ( nbUniqueNodes == 4 )
7706               iQuadFace[ nbQuad++ ] = iFace;
7707           }
7708           if (nbQuad == 2 && nbTri == 4 &&
7709               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7710             // 2 opposite quadrangles stuck with a diagonal;
7711             // sample groups of merged indices: (0-4)(2-6)
7712             // --------------------------------------------> 2 tetrahedrons
7713             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7714             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7715             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7716             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7717                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7718               // stuck with 0-2 diagonal
7719               i0  = ind1[ 3 ];
7720               i1d = ind1[ 0 ];
7721               i2  = ind1[ 1 ];
7722               i3d = ind1[ 2 ];
7723               i0t = ind2[ 1 ];
7724               i2t = ind2[ 3 ];
7725             }
7726             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7727                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7728               // stuck with 1-3 diagonal
7729               i0  = ind1[ 0 ];
7730               i1d = ind1[ 1 ];
7731               i2  = ind1[ 2 ];
7732               i3d = ind1[ 3 ];
7733               i0t = ind2[ 0 ];
7734               i2t = ind2[ 1 ];
7735             }
7736             else {
7737               ASSERT(0);
7738             }
7739             // tetrahedron 1
7740             uniqueNodes[ 0 ] = curNodes [ i0 ];
7741             uniqueNodes[ 1 ] = curNodes [ i1d ];
7742             uniqueNodes[ 2 ] = curNodes [ i3d ];
7743             uniqueNodes[ 3 ] = curNodes [ i0t ];
7744             nbUniqueNodes = 4;
7745             // tetrahedron 2
7746             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7747                                                          curNodes[ i2 ],
7748                                                          curNodes[ i3d ],
7749                                                          curNodes[ i2t ]);
7750             myLastCreatedElems.Append(newElem);
7751             if ( aShapeId )
7752               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7753             isOk = true;
7754           }
7755           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7756                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7757             // --------------------------------------------> prism
7758             // find 2 opposite triangles
7759             nbUniqueNodes = 6;
7760             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7761               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7762                 // find indices of kept and replaced nodes
7763                 // and fill unique nodes of 2 opposite triangles
7764                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7765                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7766                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7767                 // fill unique nodes
7768                 iUnique = 0;
7769                 isOk = true;
7770                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7771                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7772                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7773                   if ( n == nInit ) {
7774                     // iCur of a linked node of the opposite face (make normals co-directed):
7775                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7776                     // check that correspondent corners of triangles are linked
7777                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7778                       isOk = false;
7779                     else {
7780                       uniqueNodes[ iUnique ] = n;
7781                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7782                       iUnique++;
7783                     }
7784                   }
7785                 }
7786                 break;
7787               }
7788             }
7789           }
7790         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7791         break;
7792       } // HEXAHEDRON
7793
7794       default:
7795         isOk = false;
7796       } // switch ( nbNodes )
7797
7798     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7799
7800     if ( isOk ) {
7801       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7802         // Change nodes of polyedre
7803         const SMDS_VtkVolume* aPolyedre =
7804           dynamic_cast<const SMDS_VtkVolume*>( elem );
7805         if (aPolyedre) {
7806           int nbFaces = aPolyedre->NbFaces();
7807
7808           vector<const SMDS_MeshNode *> poly_nodes;
7809           vector<int> quantities (nbFaces);
7810
7811           for (int iface = 1; iface <= nbFaces; iface++) {
7812             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7813             quantities[iface - 1] = nbFaceNodes;
7814
7815             for (inode = 1; inode <= nbFaceNodes; inode++) {
7816               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7817
7818               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7819               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7820                 curNode = (*nnIt).second;
7821               }
7822               poly_nodes.push_back(curNode);
7823             }
7824           }
7825           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7826         }
7827       }
7828       else {
7829         int elemId = elem->GetID();
7830         //MESSAGE("Change regular element or polygon " << elemId);
7831         SMDSAbs_ElementType etyp = elem->GetType();
7832         uniqueNodes.resize(nbUniqueNodes);
7833         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, false);
7834         if (newElem)
7835           {
7836             myLastCreatedElems.Append(newElem);
7837             if ( aShapeId )
7838               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7839           }
7840         aMesh->RemoveElement(elem);
7841       }
7842     }
7843     else {
7844       // Remove invalid regular element or invalid polygon
7845       //MESSAGE("Remove invalid " << elem->GetID());
7846       rmElemIds.push_back( elem->GetID() );
7847     }
7848
7849   } // loop on elements
7850
7851   // Remove bad elements, then equal nodes (order important)
7852
7853   Remove( rmElemIds, false );
7854   Remove( rmNodeIds, true );
7855
7856 }
7857
7858
7859 // ========================================================
7860 // class   : SortableElement
7861 // purpose : allow sorting elements basing on their nodes
7862 // ========================================================
7863 class SortableElement : public set <const SMDS_MeshElement*>
7864 {
7865 public:
7866
7867   SortableElement( const SMDS_MeshElement* theElem )
7868   {
7869     myElem = theElem;
7870     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7871     while ( nodeIt->more() )
7872       this->insert( nodeIt->next() );
7873   }
7874
7875   const SMDS_MeshElement* Get() const
7876   { return myElem; }
7877
7878   void Set(const SMDS_MeshElement* e) const
7879   { myElem = e; }
7880
7881
7882 private:
7883   mutable const SMDS_MeshElement* myElem;
7884 };
7885
7886 //=======================================================================
7887 //function : FindEqualElements
7888 //purpose  : Return list of group of elements built on the same nodes.
7889 //           Search among theElements or in the whole mesh if theElements is empty
7890 //=======================================================================
7891 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7892                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7893 {
7894   myLastCreatedElems.Clear();
7895   myLastCreatedNodes.Clear();
7896
7897   typedef set<const SMDS_MeshElement*> TElemsSet;
7898   typedef map< SortableElement, int > TMapOfNodeSet;
7899   typedef list<int> TGroupOfElems;
7900
7901   TElemsSet elems;
7902   if ( theElements.empty() )
7903   { // get all elements in the mesh
7904     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7905     while ( eIt->more() )
7906       elems.insert( elems.end(), eIt->next());
7907   }
7908   else
7909     elems = theElements;
7910
7911   vector< TGroupOfElems > arrayOfGroups;
7912   TGroupOfElems groupOfElems;
7913   TMapOfNodeSet mapOfNodeSet;
7914
7915   TElemsSet::iterator elemIt = elems.begin();
7916   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7917     const SMDS_MeshElement* curElem = *elemIt;
7918     SortableElement SE(curElem);
7919     int ind = -1;
7920     // check uniqueness
7921     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7922     if( !(pp.second) ) {
7923       TMapOfNodeSet::iterator& itSE = pp.first;
7924       ind = (*itSE).second;
7925       arrayOfGroups[ind].push_back(curElem->GetID());
7926     }
7927     else {
7928       groupOfElems.clear();
7929       groupOfElems.push_back(curElem->GetID());
7930       arrayOfGroups.push_back(groupOfElems);
7931       i++;
7932     }
7933   }
7934
7935   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7936   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7937     groupOfElems = *groupIt;
7938     if ( groupOfElems.size() > 1 ) {
7939       groupOfElems.sort();
7940       theGroupsOfElementsID.push_back(groupOfElems);
7941     }
7942   }
7943 }
7944
7945 //=======================================================================
7946 //function : MergeElements
7947 //purpose  : In each given group, substitute all elements by the first one.
7948 //=======================================================================
7949
7950 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7951 {
7952   myLastCreatedElems.Clear();
7953   myLastCreatedNodes.Clear();
7954
7955   typedef list<int> TListOfIDs;
7956   TListOfIDs rmElemIds; // IDs of elems to remove
7957
7958   SMESHDS_Mesh* aMesh = GetMeshDS();
7959
7960   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7961   while ( groupsIt != theGroupsOfElementsID.end() ) {
7962     TListOfIDs& aGroupOfElemID = *groupsIt;
7963     aGroupOfElemID.sort();
7964     int elemIDToKeep = aGroupOfElemID.front();
7965     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7966     aGroupOfElemID.pop_front();
7967     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7968     while ( idIt != aGroupOfElemID.end() ) {
7969       int elemIDToRemove = *idIt;
7970       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7971       // add the kept element in groups of removed one (PAL15188)
7972       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7973       rmElemIds.push_back( elemIDToRemove );
7974       ++idIt;
7975     }
7976     ++groupsIt;
7977   }
7978
7979   Remove( rmElemIds, false );
7980 }
7981
7982 //=======================================================================
7983 //function : MergeEqualElements
7984 //purpose  : Remove all but one of elements built on the same nodes.
7985 //=======================================================================
7986
7987 void SMESH_MeshEditor::MergeEqualElements()
7988 {
7989   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7990                                                  to merge equal elements in the whole mesh */
7991   TListOfListOfElementsID aGroupsOfElementsID;
7992   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7993   MergeElements(aGroupsOfElementsID);
7994 }
7995
7996 //=======================================================================
7997 //function : FindFaceInSet
7998 //purpose  : Return a face having linked nodes n1 and n2 and which is
7999 //           - not in avoidSet,
8000 //           - in elemSet provided that !elemSet.empty()
8001 //           i1 and i2 optionally returns indices of n1 and n2
8002 //=======================================================================
8003
8004 const SMDS_MeshElement*
8005 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8006                                 const SMDS_MeshNode*    n2,
8007                                 const TIDSortedElemSet& elemSet,
8008                                 const TIDSortedElemSet& avoidSet,
8009                                 int*                    n1ind,
8010                                 int*                    n2ind)
8011
8012 {
8013   int i1, i2;
8014   const SMDS_MeshElement* face = 0;
8015
8016   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8017   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8018   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8019   {
8020     //MESSAGE("in while ( invElemIt->more() && !face )");
8021     const SMDS_MeshElement* elem = invElemIt->next();
8022     if (avoidSet.count( elem ))
8023       continue;
8024     if ( !elemSet.empty() && !elemSet.count( elem ))
8025       continue;
8026     // index of n1
8027     i1 = elem->GetNodeIndex( n1 );
8028     // find a n2 linked to n1
8029     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8030     for ( int di = -1; di < 2 && !face; di += 2 )
8031     {
8032       i2 = (i1+di+nbN) % nbN;
8033       if ( elem->GetNode( i2 ) == n2 )
8034         face = elem;
8035     }
8036     if ( !face && elem->IsQuadratic())
8037     {
8038       // analysis for quadratic elements using all nodes
8039       const SMDS_VtkFace* F =
8040         dynamic_cast<const SMDS_VtkFace*>(elem);
8041       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8042       // use special nodes iterator
8043       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8044       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8045       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8046       {
8047         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8048         if ( n1 == prevN && n2 == n )
8049         {
8050           face = elem;
8051         }
8052         else if ( n2 == prevN && n1 == n )
8053         {
8054           face = elem; swap( i1, i2 );
8055         }
8056         prevN = n;
8057       }
8058     }
8059   }
8060   if ( n1ind ) *n1ind = i1;
8061   if ( n2ind ) *n2ind = i2;
8062   return face;
8063 }
8064
8065 //=======================================================================
8066 //function : findAdjacentFace
8067 //purpose  :
8068 //=======================================================================
8069
8070 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8071                                                 const SMDS_MeshNode* n2,
8072                                                 const SMDS_MeshElement* elem)
8073 {
8074   TIDSortedElemSet elemSet, avoidSet;
8075   if ( elem )
8076     avoidSet.insert ( elem );
8077   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8078 }
8079
8080 //=======================================================================
8081 //function : FindFreeBorder
8082 //purpose  :
8083 //=======================================================================
8084
8085 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8086
8087 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8088                                        const SMDS_MeshNode*             theSecondNode,
8089                                        const SMDS_MeshNode*             theLastNode,
8090                                        list< const SMDS_MeshNode* > &   theNodes,
8091                                        list< const SMDS_MeshElement* >& theFaces)
8092 {
8093   if ( !theFirstNode || !theSecondNode )
8094     return false;
8095   // find border face between theFirstNode and theSecondNode
8096   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8097   if ( !curElem )
8098     return false;
8099
8100   theFaces.push_back( curElem );
8101   theNodes.push_back( theFirstNode );
8102   theNodes.push_back( theSecondNode );
8103
8104   //vector<const SMDS_MeshNode*> nodes;
8105   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8106   TIDSortedElemSet foundElems;
8107   bool needTheLast = ( theLastNode != 0 );
8108
8109   while ( nStart != theLastNode ) {
8110     if ( nStart == theFirstNode )
8111       return !needTheLast;
8112
8113     // find all free border faces sharing form nStart
8114
8115     list< const SMDS_MeshElement* > curElemList;
8116     list< const SMDS_MeshNode* > nStartList;
8117     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8118     while ( invElemIt->more() ) {
8119       const SMDS_MeshElement* e = invElemIt->next();
8120       if ( e == curElem || foundElems.insert( e ).second ) {
8121         // get nodes
8122         int iNode = 0, nbNodes = e->NbNodes();
8123         //const SMDS_MeshNode* nodes[nbNodes+1];
8124         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8125
8126         if(e->IsQuadratic()) {
8127           const SMDS_VtkFace* F =
8128             dynamic_cast<const SMDS_VtkFace*>(e);
8129           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8130           // use special nodes iterator
8131           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8132           while( anIter->more() ) {
8133             nodes[ iNode++ ] = cast2Node(anIter->next());
8134           }
8135         }
8136         else {
8137           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8138           while ( nIt->more() )
8139             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8140         }
8141         nodes[ iNode ] = nodes[ 0 ];
8142         // check 2 links
8143         for ( iNode = 0; iNode < nbNodes; iNode++ )
8144           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8145                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8146               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8147           {
8148             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8149             curElemList.push_back( e );
8150           }
8151       }
8152     }
8153     // analyse the found
8154
8155     int nbNewBorders = curElemList.size();
8156     if ( nbNewBorders == 0 ) {
8157       // no free border furthermore
8158       return !needTheLast;
8159     }
8160     else if ( nbNewBorders == 1 ) {
8161       // one more element found
8162       nIgnore = nStart;
8163       nStart = nStartList.front();
8164       curElem = curElemList.front();
8165       theFaces.push_back( curElem );
8166       theNodes.push_back( nStart );
8167     }
8168     else {
8169       // several continuations found
8170       list< const SMDS_MeshElement* >::iterator curElemIt;
8171       list< const SMDS_MeshNode* >::iterator nStartIt;
8172       // check if one of them reached the last node
8173       if ( needTheLast ) {
8174         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8175              curElemIt!= curElemList.end();
8176              curElemIt++, nStartIt++ )
8177           if ( *nStartIt == theLastNode ) {
8178             theFaces.push_back( *curElemIt );
8179             theNodes.push_back( *nStartIt );
8180             return true;
8181           }
8182       }
8183       // find the best free border by the continuations
8184       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8185       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8186       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8187            curElemIt!= curElemList.end();
8188            curElemIt++, nStartIt++ )
8189       {
8190         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8191         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8192         // find one more free border
8193         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8194           cNL->clear();
8195           cFL->clear();
8196         }
8197         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8198           // choice: clear a worse one
8199           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8200           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8201           contNodes[ iWorse ].clear();
8202           contFaces[ iWorse ].clear();
8203         }
8204       }
8205       if ( contNodes[0].empty() && contNodes[1].empty() )
8206         return false;
8207
8208       // append the best free border
8209       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8210       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8211       theNodes.pop_back(); // remove nIgnore
8212       theNodes.pop_back(); // remove nStart
8213       theFaces.pop_back(); // remove curElem
8214       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8215       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8216       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8217       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8218       return true;
8219
8220     } // several continuations found
8221   } // while ( nStart != theLastNode )
8222
8223   return true;
8224 }
8225
8226 //=======================================================================
8227 //function : CheckFreeBorderNodes
8228 //purpose  : Return true if the tree nodes are on a free border
8229 //=======================================================================
8230
8231 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8232                                             const SMDS_MeshNode* theNode2,
8233                                             const SMDS_MeshNode* theNode3)
8234 {
8235   list< const SMDS_MeshNode* > nodes;
8236   list< const SMDS_MeshElement* > faces;
8237   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8238 }
8239
8240 //=======================================================================
8241 //function : SewFreeBorder
8242 //purpose  :
8243 //=======================================================================
8244
8245 SMESH_MeshEditor::Sew_Error
8246 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8247                                  const SMDS_MeshNode* theBordSecondNode,
8248                                  const SMDS_MeshNode* theBordLastNode,
8249                                  const SMDS_MeshNode* theSideFirstNode,
8250                                  const SMDS_MeshNode* theSideSecondNode,
8251                                  const SMDS_MeshNode* theSideThirdNode,
8252                                  const bool           theSideIsFreeBorder,
8253                                  const bool           toCreatePolygons,
8254                                  const bool           toCreatePolyedrs)
8255 {
8256   myLastCreatedElems.Clear();
8257   myLastCreatedNodes.Clear();
8258
8259   MESSAGE("::SewFreeBorder()");
8260   Sew_Error aResult = SEW_OK;
8261
8262   // ====================================
8263   //    find side nodes and elements
8264   // ====================================
8265
8266   list< const SMDS_MeshNode* > nSide[ 2 ];
8267   list< const SMDS_MeshElement* > eSide[ 2 ];
8268   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8269   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8270
8271   // Free border 1
8272   // --------------
8273   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8274                       nSide[0], eSide[0])) {
8275     MESSAGE(" Free Border 1 not found " );
8276     aResult = SEW_BORDER1_NOT_FOUND;
8277   }
8278   if (theSideIsFreeBorder) {
8279     // Free border 2
8280     // --------------
8281     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8282                         nSide[1], eSide[1])) {
8283       MESSAGE(" Free Border 2 not found " );
8284       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8285     }
8286   }
8287   if ( aResult != SEW_OK )
8288     return aResult;
8289
8290   if (!theSideIsFreeBorder) {
8291     // Side 2
8292     // --------------
8293
8294     // -------------------------------------------------------------------------
8295     // Algo:
8296     // 1. If nodes to merge are not coincident, move nodes of the free border
8297     //    from the coord sys defined by the direction from the first to last
8298     //    nodes of the border to the correspondent sys of the side 2
8299     // 2. On the side 2, find the links most co-directed with the correspondent
8300     //    links of the free border
8301     // -------------------------------------------------------------------------
8302
8303     // 1. Since sewing may break if there are volumes to split on the side 2,
8304     //    we wont move nodes but just compute new coordinates for them
8305     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8306     TNodeXYZMap nBordXYZ;
8307     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8308     list< const SMDS_MeshNode* >::iterator nBordIt;
8309
8310     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8311     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8312     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8313     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8314     double tol2 = 1.e-8;
8315     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8316     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8317       // Need node movement.
8318
8319       // find X and Z axes to create trsf
8320       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8321       gp_Vec X = Zs ^ Zb;
8322       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8323         // Zb || Zs
8324         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8325
8326       // coord systems
8327       gp_Ax3 toBordAx( Pb1, Zb, X );
8328       gp_Ax3 fromSideAx( Ps1, Zs, X );
8329       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8330       // set trsf
8331       gp_Trsf toBordSys, fromSide2Sys;
8332       toBordSys.SetTransformation( toBordAx );
8333       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8334       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8335
8336       // move
8337       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8338         const SMDS_MeshNode* n = *nBordIt;
8339         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8340         toBordSys.Transforms( xyz );
8341         fromSide2Sys.Transforms( xyz );
8342         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8343       }
8344     }
8345     else {
8346       // just insert nodes XYZ in the nBordXYZ map
8347       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8348         const SMDS_MeshNode* n = *nBordIt;
8349         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8350       }
8351     }
8352
8353     // 2. On the side 2, find the links most co-directed with the correspondent
8354     //    links of the free border
8355
8356     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8357     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8358     sideNodes.push_back( theSideFirstNode );
8359
8360     bool hasVolumes = false;
8361     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8362     set<long> foundSideLinkIDs, checkedLinkIDs;
8363     SMDS_VolumeTool volume;
8364     //const SMDS_MeshNode* faceNodes[ 4 ];
8365
8366     const SMDS_MeshNode*    sideNode;
8367     const SMDS_MeshElement* sideElem;
8368     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8369     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8370     nBordIt = bordNodes.begin();
8371     nBordIt++;
8372     // border node position and border link direction to compare with
8373     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8374     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8375     // choose next side node by link direction or by closeness to
8376     // the current border node:
8377     bool searchByDir = ( *nBordIt != theBordLastNode );
8378     do {
8379       // find the next node on the Side 2
8380       sideNode = 0;
8381       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8382       long linkID;
8383       checkedLinkIDs.clear();
8384       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8385
8386       // loop on inverse elements of current node (prevSideNode) on the Side 2
8387       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8388       while ( invElemIt->more() )
8389       {
8390         const SMDS_MeshElement* elem = invElemIt->next();
8391         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8392         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8393         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8394         bool isVolume = volume.Set( elem );
8395         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8396         if ( isVolume ) // --volume
8397           hasVolumes = true;
8398         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8399           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8400           if(elem->IsQuadratic()) {
8401             const SMDS_VtkFace* F =
8402               dynamic_cast<const SMDS_VtkFace*>(elem);
8403             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8404             // use special nodes iterator
8405             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8406             while( anIter->more() ) {
8407               nodes[ iNode ] = cast2Node(anIter->next());
8408               if ( nodes[ iNode++ ] == prevSideNode )
8409                 iPrevNode = iNode - 1;
8410             }
8411           }
8412           else {
8413             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8414             while ( nIt->more() ) {
8415               nodes[ iNode ] = cast2Node( nIt->next() );
8416               if ( nodes[ iNode++ ] == prevSideNode )
8417                 iPrevNode = iNode - 1;
8418             }
8419           }
8420           // there are 2 links to check
8421           nbNodes = 2;
8422         }
8423         else // --edge
8424           continue;
8425         // loop on links, to be precise, on the second node of links
8426         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8427           const SMDS_MeshNode* n = nodes[ iNode ];
8428           if ( isVolume ) {
8429             if ( !volume.IsLinked( n, prevSideNode ))
8430               continue;
8431           }
8432           else {
8433             if ( iNode ) // a node before prevSideNode
8434               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8435             else         // a node after prevSideNode
8436               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8437           }
8438           // check if this link was already used
8439           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8440           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8441           if (!isJustChecked &&
8442               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8443           {
8444             // test a link geometrically
8445             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8446             bool linkIsBetter = false;
8447             double dot = 0.0, dist = 0.0;
8448             if ( searchByDir ) { // choose most co-directed link
8449               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8450               linkIsBetter = ( dot > maxDot );
8451             }
8452             else { // choose link with the node closest to bordPos
8453               dist = ( nextXYZ - bordPos ).SquareModulus();
8454               linkIsBetter = ( dist < minDist );
8455             }
8456             if ( linkIsBetter ) {
8457               maxDot = dot;
8458               minDist = dist;
8459               linkID = iLink;
8460               sideNode = n;
8461               sideElem = elem;
8462             }
8463           }
8464         }
8465       } // loop on inverse elements of prevSideNode
8466
8467       if ( !sideNode ) {
8468         MESSAGE(" Cant find path by links of the Side 2 ");
8469         return SEW_BAD_SIDE_NODES;
8470       }
8471       sideNodes.push_back( sideNode );
8472       sideElems.push_back( sideElem );
8473       foundSideLinkIDs.insert ( linkID );
8474       prevSideNode = sideNode;
8475
8476       if ( *nBordIt == theBordLastNode )
8477         searchByDir = false;
8478       else {
8479         // find the next border link to compare with
8480         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8481         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8482         // move to next border node if sideNode is before forward border node (bordPos)
8483         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8484           prevBordNode = *nBordIt;
8485           nBordIt++;
8486           bordPos = nBordXYZ[ *nBordIt ];
8487           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8488           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8489         }
8490       }
8491     }
8492     while ( sideNode != theSideSecondNode );
8493
8494     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8495       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8496       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8497     }
8498   } // end nodes search on the side 2
8499
8500   // ============================
8501   // sew the border to the side 2
8502   // ============================
8503
8504   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8505   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8506
8507   TListOfListOfNodes nodeGroupsToMerge;
8508   if ( nbNodes[0] == nbNodes[1] ||
8509        ( theSideIsFreeBorder && !theSideThirdNode)) {
8510
8511     // all nodes are to be merged
8512
8513     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8514          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8515          nIt[0]++, nIt[1]++ )
8516     {
8517       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8518       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8519       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8520     }
8521   }
8522   else {
8523
8524     // insert new nodes into the border and the side to get equal nb of segments
8525
8526     // get normalized parameters of nodes on the borders
8527     //double param[ 2 ][ maxNbNodes ];
8528     double* param[ 2 ];
8529     param[0] = new double [ maxNbNodes ];
8530     param[1] = new double [ maxNbNodes ];
8531     int iNode, iBord;
8532     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8533       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8534       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8535       const SMDS_MeshNode* nPrev = *nIt;
8536       double bordLength = 0;
8537       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8538         const SMDS_MeshNode* nCur = *nIt;
8539         gp_XYZ segment (nCur->X() - nPrev->X(),
8540                         nCur->Y() - nPrev->Y(),
8541                         nCur->Z() - nPrev->Z());
8542         double segmentLen = segment.Modulus();
8543         bordLength += segmentLen;
8544         param[ iBord ][ iNode ] = bordLength;
8545         nPrev = nCur;
8546       }
8547       // normalize within [0,1]
8548       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8549         param[ iBord ][ iNode ] /= bordLength;
8550       }
8551     }
8552
8553     // loop on border segments
8554     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8555     int i[ 2 ] = { 0, 0 };
8556     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8557     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8558
8559     TElemOfNodeListMap insertMap;
8560     TElemOfNodeListMap::iterator insertMapIt;
8561     // insertMap is
8562     // key:   elem to insert nodes into
8563     // value: 2 nodes to insert between + nodes to be inserted
8564     do {
8565       bool next[ 2 ] = { false, false };
8566
8567       // find min adjacent segment length after sewing
8568       double nextParam = 10., prevParam = 0;
8569       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8570         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8571           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8572         if ( i[ iBord ] > 0 )
8573           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8574       }
8575       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8576       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8577       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8578
8579       // choose to insert or to merge nodes
8580       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8581       if ( Abs( du ) <= minSegLen * 0.2 ) {
8582         // merge
8583         // ------
8584         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8585         const SMDS_MeshNode* n0 = *nIt[0];
8586         const SMDS_MeshNode* n1 = *nIt[1];
8587         nodeGroupsToMerge.back().push_back( n1 );
8588         nodeGroupsToMerge.back().push_back( n0 );
8589         // position of node of the border changes due to merge
8590         param[ 0 ][ i[0] ] += du;
8591         // move n1 for the sake of elem shape evaluation during insertion.
8592         // n1 will be removed by MergeNodes() anyway
8593         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8594         next[0] = next[1] = true;
8595       }
8596       else {
8597         // insert
8598         // ------
8599         int intoBord = ( du < 0 ) ? 0 : 1;
8600         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8601         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8602         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8603         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8604         if ( intoBord == 1 ) {
8605           // move node of the border to be on a link of elem of the side
8606           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8607           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8608           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8609           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8610           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8611         }
8612         insertMapIt = insertMap.find( elem );
8613         bool notFound = ( insertMapIt == insertMap.end() );
8614         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8615         if ( otherLink ) {
8616           // insert into another link of the same element:
8617           // 1. perform insertion into the other link of the elem
8618           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8619           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8620           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8621           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8622           // 2. perform insertion into the link of adjacent faces
8623           while (true) {
8624             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8625             if ( adjElem )
8626               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8627             else
8628               break;
8629           }
8630           if (toCreatePolyedrs) {
8631             // perform insertion into the links of adjacent volumes
8632             UpdateVolumes(n12, n22, nodeList);
8633           }
8634           // 3. find an element appeared on n1 and n2 after the insertion
8635           insertMap.erase( elem );
8636           elem = findAdjacentFace( n1, n2, 0 );
8637         }
8638         if ( notFound || otherLink ) {
8639           // add element and nodes of the side into the insertMap
8640           insertMapIt = insertMap.insert
8641             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8642           (*insertMapIt).second.push_back( n1 );
8643           (*insertMapIt).second.push_back( n2 );
8644         }
8645         // add node to be inserted into elem
8646         (*insertMapIt).second.push_back( nIns );
8647         next[ 1 - intoBord ] = true;
8648       }
8649
8650       // go to the next segment
8651       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8652         if ( next[ iBord ] ) {
8653           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8654             eIt[ iBord ]++;
8655           nPrev[ iBord ] = *nIt[ iBord ];
8656           nIt[ iBord ]++; i[ iBord ]++;
8657         }
8658       }
8659     }
8660     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8661
8662     // perform insertion of nodes into elements
8663
8664     for (insertMapIt = insertMap.begin();
8665          insertMapIt != insertMap.end();
8666          insertMapIt++ )
8667     {
8668       const SMDS_MeshElement* elem = (*insertMapIt).first;
8669       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8670       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8671       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8672
8673       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8674
8675       if ( !theSideIsFreeBorder ) {
8676         // look for and insert nodes into the faces adjacent to elem
8677         while (true) {
8678           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8679           if ( adjElem )
8680             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8681           else
8682             break;
8683         }
8684       }
8685       if (toCreatePolyedrs) {
8686         // perform insertion into the links of adjacent volumes
8687         UpdateVolumes(n1, n2, nodeList);
8688       }
8689     }
8690
8691     delete param[0];
8692     delete param[1];
8693   } // end: insert new nodes
8694
8695   MergeNodes ( nodeGroupsToMerge );
8696
8697   return aResult;
8698 }
8699
8700 //=======================================================================
8701 //function : InsertNodesIntoLink
8702 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8703 //           and theBetweenNode2 and split theElement
8704 //=======================================================================
8705
8706 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8707                                            const SMDS_MeshNode*        theBetweenNode1,
8708                                            const SMDS_MeshNode*        theBetweenNode2,
8709                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8710                                            const bool                  toCreatePoly)
8711 {
8712   if ( theFace->GetType() != SMDSAbs_Face ) return;
8713
8714   // find indices of 2 link nodes and of the rest nodes
8715   int iNode = 0, il1, il2, i3, i4;
8716   il1 = il2 = i3 = i4 = -1;
8717   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8718   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8719
8720   if(theFace->IsQuadratic()) {
8721     const SMDS_VtkFace* F =
8722       dynamic_cast<const SMDS_VtkFace*>(theFace);
8723     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8724     // use special nodes iterator
8725     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8726     while( anIter->more() ) {
8727       const SMDS_MeshNode* n = cast2Node(anIter->next());
8728       if ( n == theBetweenNode1 )
8729         il1 = iNode;
8730       else if ( n == theBetweenNode2 )
8731         il2 = iNode;
8732       else if ( i3 < 0 )
8733         i3 = iNode;
8734       else
8735         i4 = iNode;
8736       nodes[ iNode++ ] = n;
8737     }
8738   }
8739   else {
8740     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8741     while ( nodeIt->more() ) {
8742       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8743       if ( n == theBetweenNode1 )
8744         il1 = iNode;
8745       else if ( n == theBetweenNode2 )
8746         il2 = iNode;
8747       else if ( i3 < 0 )
8748         i3 = iNode;
8749       else
8750         i4 = iNode;
8751       nodes[ iNode++ ] = n;
8752     }
8753   }
8754   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8755     return ;
8756
8757   // arrange link nodes to go one after another regarding the face orientation
8758   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8759   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8760   if ( reverse ) {
8761     iNode = il1;
8762     il1 = il2;
8763     il2 = iNode;
8764     aNodesToInsert.reverse();
8765   }
8766   // check that not link nodes of a quadrangles are in good order
8767   int nbFaceNodes = theFace->NbNodes();
8768   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8769     iNode = i3;
8770     i3 = i4;
8771     i4 = iNode;
8772   }
8773
8774   if (toCreatePoly || theFace->IsPoly()) {
8775
8776     iNode = 0;
8777     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8778
8779     // add nodes of face up to first node of link
8780     bool isFLN = false;
8781
8782     if(theFace->IsQuadratic()) {
8783       const SMDS_VtkFace* F =
8784         dynamic_cast<const SMDS_VtkFace*>(theFace);
8785       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8786       // use special nodes iterator
8787       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8788       while( anIter->more()  && !isFLN ) {
8789         const SMDS_MeshNode* n = cast2Node(anIter->next());
8790         poly_nodes[iNode++] = n;
8791         if (n == nodes[il1]) {
8792           isFLN = true;
8793         }
8794       }
8795       // add nodes to insert
8796       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8797       for (; nIt != aNodesToInsert.end(); nIt++) {
8798         poly_nodes[iNode++] = *nIt;
8799       }
8800       // add nodes of face starting from last node of link
8801       while ( anIter->more() ) {
8802         poly_nodes[iNode++] = cast2Node(anIter->next());
8803       }
8804     }
8805     else {
8806       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8807       while ( nodeIt->more() && !isFLN ) {
8808         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8809         poly_nodes[iNode++] = n;
8810         if (n == nodes[il1]) {
8811           isFLN = true;
8812         }
8813       }
8814       // add nodes to insert
8815       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8816       for (; nIt != aNodesToInsert.end(); nIt++) {
8817         poly_nodes[iNode++] = *nIt;
8818       }
8819       // add nodes of face starting from last node of link
8820       while ( nodeIt->more() ) {
8821         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8822         poly_nodes[iNode++] = n;
8823       }
8824     }
8825
8826     // edit or replace the face
8827     SMESHDS_Mesh *aMesh = GetMeshDS();
8828
8829     if (theFace->IsPoly()) {
8830       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8831     }
8832     else {
8833       int aShapeId = FindShape( theFace );
8834
8835       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8836       myLastCreatedElems.Append(newElem);
8837       if ( aShapeId && newElem )
8838         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8839
8840       aMesh->RemoveElement(theFace);
8841     }
8842     return;
8843   }
8844
8845   SMESHDS_Mesh *aMesh = GetMeshDS();
8846   if( !theFace->IsQuadratic() ) {
8847
8848     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8849     int nbLinkNodes = 2 + aNodesToInsert.size();
8850     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8851     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8852     linkNodes[ 0 ] = nodes[ il1 ];
8853     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8854     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8855     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8856       linkNodes[ iNode++ ] = *nIt;
8857     }
8858     // decide how to split a quadrangle: compare possible variants
8859     // and choose which of splits to be a quadrangle
8860     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8861     if ( nbFaceNodes == 3 ) {
8862       iBestQuad = nbSplits;
8863       i4 = i3;
8864     }
8865     else if ( nbFaceNodes == 4 ) {
8866       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8867       double aBestRate = DBL_MAX;
8868       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8869         i1 = 0; i2 = 1;
8870         double aBadRate = 0;
8871         // evaluate elements quality
8872         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8873           if ( iSplit == iQuad ) {
8874             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8875                                    linkNodes[ i2++ ],
8876                                    nodes[ i3 ],
8877                                    nodes[ i4 ]);
8878             aBadRate += getBadRate( &quad, aCrit );
8879           }
8880           else {
8881             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8882                                    linkNodes[ i2++ ],
8883                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8884             aBadRate += getBadRate( &tria, aCrit );
8885           }
8886         }
8887         // choice
8888         if ( aBadRate < aBestRate ) {
8889           iBestQuad = iQuad;
8890           aBestRate = aBadRate;
8891         }
8892       }
8893     }
8894
8895     // create new elements
8896     int aShapeId = FindShape( theFace );
8897
8898     i1 = 0; i2 = 1;
8899     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8900       SMDS_MeshElement* newElem = 0;
8901       if ( iSplit == iBestQuad )
8902         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8903                                   linkNodes[ i2++ ],
8904                                   nodes[ i3 ],
8905                                   nodes[ i4 ]);
8906       else
8907         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8908                                   linkNodes[ i2++ ],
8909                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8910       myLastCreatedElems.Append(newElem);
8911       if ( aShapeId && newElem )
8912         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8913     }
8914
8915     // change nodes of theFace
8916     const SMDS_MeshNode* newNodes[ 4 ];
8917     newNodes[ 0 ] = linkNodes[ i1 ];
8918     newNodes[ 1 ] = linkNodes[ i2 ];
8919     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8920     newNodes[ 3 ] = nodes[ i4 ];
8921     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8922     const SMDS_MeshElement* newElem = 0;
8923     if (iSplit == iBestQuad)
8924       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8925     else
8926       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8927     myLastCreatedElems.Append(newElem);
8928     if ( aShapeId && newElem )
8929       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8930 } // end if(!theFace->IsQuadratic())
8931   else { // theFace is quadratic
8932     // we have to split theFace on simple triangles and one simple quadrangle
8933     int tmp = il1/2;
8934     int nbshift = tmp*2;
8935     // shift nodes in nodes[] by nbshift
8936     int i,j;
8937     for(i=0; i<nbshift; i++) {
8938       const SMDS_MeshNode* n = nodes[0];
8939       for(j=0; j<nbFaceNodes-1; j++) {
8940         nodes[j] = nodes[j+1];
8941       }
8942       nodes[nbFaceNodes-1] = n;
8943     }
8944     il1 = il1 - nbshift;
8945     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8946     //   n0      n1     n2    n0      n1     n2
8947     //     +-----+-----+        +-----+-----+
8948     //      \         /         |           |
8949     //       \       /          |           |
8950     //      n5+     +n3       n7+           +n3
8951     //         \   /            |           |
8952     //          \ /             |           |
8953     //           +              +-----+-----+
8954     //           n4           n6      n5     n4
8955
8956     // create new elements
8957     int aShapeId = FindShape( theFace );
8958
8959     int n1,n2,n3;
8960     if(nbFaceNodes==6) { // quadratic triangle
8961       SMDS_MeshElement* newElem =
8962         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8963       myLastCreatedElems.Append(newElem);
8964       if ( aShapeId && newElem )
8965         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8966       if(theFace->IsMediumNode(nodes[il1])) {
8967         // create quadrangle
8968         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8969         myLastCreatedElems.Append(newElem);
8970         if ( aShapeId && newElem )
8971           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8972         n1 = 1;
8973         n2 = 2;
8974         n3 = 3;
8975       }
8976       else {
8977         // create quadrangle
8978         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8979         myLastCreatedElems.Append(newElem);
8980         if ( aShapeId && newElem )
8981           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8982         n1 = 0;
8983         n2 = 1;
8984         n3 = 5;
8985       }
8986     }
8987     else { // nbFaceNodes==8 - quadratic quadrangle
8988       SMDS_MeshElement* newElem =
8989         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8990       myLastCreatedElems.Append(newElem);
8991       if ( aShapeId && newElem )
8992         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8993       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8994       myLastCreatedElems.Append(newElem);
8995       if ( aShapeId && newElem )
8996         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8997       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8998       myLastCreatedElems.Append(newElem);
8999       if ( aShapeId && newElem )
9000         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9001       if(theFace->IsMediumNode(nodes[il1])) {
9002         // create quadrangle
9003         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9004         myLastCreatedElems.Append(newElem);
9005         if ( aShapeId && newElem )
9006           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9007         n1 = 1;
9008         n2 = 2;
9009         n3 = 3;
9010       }
9011       else {
9012         // create quadrangle
9013         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9014         myLastCreatedElems.Append(newElem);
9015         if ( aShapeId && newElem )
9016           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9017         n1 = 0;
9018         n2 = 1;
9019         n3 = 7;
9020       }
9021     }
9022     // create needed triangles using n1,n2,n3 and inserted nodes
9023     int nbn = 2 + aNodesToInsert.size();
9024     //const SMDS_MeshNode* aNodes[nbn];
9025     vector<const SMDS_MeshNode*> aNodes(nbn);
9026     aNodes[0] = nodes[n1];
9027     aNodes[nbn-1] = nodes[n2];
9028     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9029     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9030       aNodes[iNode++] = *nIt;
9031     }
9032     for(i=1; i<nbn; i++) {
9033       SMDS_MeshElement* newElem =
9034         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9035       myLastCreatedElems.Append(newElem);
9036       if ( aShapeId && newElem )
9037         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9038     }
9039   }
9040   // remove old face
9041   aMesh->RemoveElement(theFace);
9042 }
9043
9044 //=======================================================================
9045 //function : UpdateVolumes
9046 //purpose  :
9047 //=======================================================================
9048 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9049                                       const SMDS_MeshNode*        theBetweenNode2,
9050                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9051 {
9052   myLastCreatedElems.Clear();
9053   myLastCreatedNodes.Clear();
9054
9055   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9056   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9057     const SMDS_MeshElement* elem = invElemIt->next();
9058
9059     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9060     SMDS_VolumeTool aVolume (elem);
9061     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9062       continue;
9063
9064     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9065     int iface, nbFaces = aVolume.NbFaces();
9066     vector<const SMDS_MeshNode *> poly_nodes;
9067     vector<int> quantities (nbFaces);
9068
9069     for (iface = 0; iface < nbFaces; iface++) {
9070       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9071       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9072       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9073
9074       for (int inode = 0; inode < nbFaceNodes; inode++) {
9075         poly_nodes.push_back(faceNodes[inode]);
9076
9077         if (nbInserted == 0) {
9078           if (faceNodes[inode] == theBetweenNode1) {
9079             if (faceNodes[inode + 1] == theBetweenNode2) {
9080               nbInserted = theNodesToInsert.size();
9081
9082               // add nodes to insert
9083               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9084               for (; nIt != theNodesToInsert.end(); nIt++) {
9085                 poly_nodes.push_back(*nIt);
9086               }
9087             }
9088           }
9089           else if (faceNodes[inode] == theBetweenNode2) {
9090             if (faceNodes[inode + 1] == theBetweenNode1) {
9091               nbInserted = theNodesToInsert.size();
9092
9093               // add nodes to insert in reversed order
9094               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9095               nIt--;
9096               for (; nIt != theNodesToInsert.begin(); nIt--) {
9097                 poly_nodes.push_back(*nIt);
9098               }
9099               poly_nodes.push_back(*nIt);
9100             }
9101           }
9102           else {
9103           }
9104         }
9105       }
9106       quantities[iface] = nbFaceNodes + nbInserted;
9107     }
9108
9109     // Replace or update the volume
9110     SMESHDS_Mesh *aMesh = GetMeshDS();
9111
9112     if (elem->IsPoly()) {
9113       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9114
9115     }
9116     else {
9117       int aShapeId = FindShape( elem );
9118
9119       SMDS_MeshElement* newElem =
9120         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9121       myLastCreatedElems.Append(newElem);
9122       if (aShapeId && newElem)
9123         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9124
9125       aMesh->RemoveElement(elem);
9126     }
9127   }
9128 }
9129
9130 //=======================================================================
9131 /*!
9132  * \brief Convert elements contained in a submesh to quadratic
9133  * \retval int - nb of checked elements
9134  */
9135 //=======================================================================
9136
9137 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9138                                              SMESH_MesherHelper& theHelper,
9139                                              const bool          theForce3d)
9140 {
9141   int nbElem = 0;
9142   if( !theSm ) return nbElem;
9143
9144   vector<int> nbNodeInFaces;
9145   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9146   while(ElemItr->more())
9147   {
9148     nbElem++;
9149     const SMDS_MeshElement* elem = ElemItr->next();
9150     if( !elem || elem->IsQuadratic() ) continue;
9151
9152     int id = elem->GetID();
9153     //MESSAGE("elem " << id);
9154     id = 0; // get a free number for new elements
9155     int nbNodes = elem->NbNodes();
9156     SMDSAbs_ElementType aType = elem->GetType();
9157
9158     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9159     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9160       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9161
9162     const SMDS_MeshElement* NewElem = 0;
9163
9164     switch( aType )
9165     {
9166     case SMDSAbs_Edge :
9167       {
9168         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9169         break;
9170       }
9171     case SMDSAbs_Face :
9172       {
9173         switch(nbNodes)
9174         {
9175         case 3:
9176           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9177           break;
9178         case 4:
9179           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9180           break;
9181         default:
9182           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9183           continue;
9184         }
9185         break;
9186       }
9187     case SMDSAbs_Volume :
9188       {
9189         switch(nbNodes)
9190         {
9191         case 4:
9192           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9193           break;
9194         case 5:
9195           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9196           break;
9197         case 6:
9198           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9199           break;
9200         case 8:
9201           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9202                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9203           break;
9204         default:
9205           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9206         }
9207         break;
9208       }
9209     default :
9210       continue;
9211     }
9212     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9213     if( NewElem )
9214       theSm->AddElement( NewElem );
9215
9216     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9217   }
9218 //  if (!GetMeshDS()->isCompacted())
9219 //    GetMeshDS()->compactMesh();
9220   return nbElem;
9221 }
9222
9223 //=======================================================================
9224 //function : ConvertToQuadratic
9225 //purpose  :
9226 //=======================================================================
9227 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9228 {
9229   SMESHDS_Mesh* meshDS = GetMeshDS();
9230
9231   SMESH_MesherHelper aHelper(*myMesh);
9232   aHelper.SetIsQuadratic( true );
9233
9234   int nbCheckedElems = 0;
9235   if ( myMesh->HasShapeToMesh() )
9236   {
9237     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9238     {
9239       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9240       while ( smIt->more() ) {
9241         SMESH_subMesh* sm = smIt->next();
9242         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9243           aHelper.SetSubShape( sm->GetSubShape() );
9244           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9245         }
9246       }
9247     }
9248   }
9249   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9250   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9251   {
9252     SMESHDS_SubMesh *smDS = 0;
9253     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9254     while(aEdgeItr->more())
9255     {
9256       const SMDS_MeshEdge* edge = aEdgeItr->next();
9257       if(edge && !edge->IsQuadratic())
9258       {
9259         int id = edge->GetID();
9260         //MESSAGE("edge->GetID() " << id);
9261         const SMDS_MeshNode* n1 = edge->GetNode(0);
9262         const SMDS_MeshNode* n2 = edge->GetNode(1);
9263
9264         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9265
9266         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9267         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9268       }
9269     }
9270     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9271     while(aFaceItr->more())
9272     {
9273       const SMDS_MeshFace* face = aFaceItr->next();
9274       if(!face || face->IsQuadratic() ) continue;
9275
9276       int id = face->GetID();
9277       int nbNodes = face->NbNodes();
9278       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9279
9280       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9281
9282       SMDS_MeshFace * NewFace = 0;
9283       switch(nbNodes)
9284       {
9285       case 3:
9286         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9287         break;
9288       case 4:
9289         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9290         break;
9291       default:
9292         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9293       }
9294       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9295     }
9296     vector<int> nbNodeInFaces;
9297     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9298     while(aVolumeItr->more())
9299     {
9300       const SMDS_MeshVolume* volume = aVolumeItr->next();
9301       if(!volume || volume->IsQuadratic() ) continue;
9302
9303       int id = volume->GetID();
9304       int nbNodes = volume->NbNodes();
9305       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9306       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9307         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9308
9309       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9310
9311       SMDS_MeshVolume * NewVolume = 0;
9312       switch(nbNodes)
9313       {
9314       case 4:
9315         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9316                                       nodes[3], id, theForce3d );
9317         break;
9318       case 5:
9319         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9320                                       nodes[3], nodes[4], id, theForce3d);
9321         break;
9322       case 6:
9323         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9324                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9325         break;
9326       case 8:
9327         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9328                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9329         break;
9330       default:
9331         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9332       }
9333       ReplaceElemInGroups(volume, NewVolume, meshDS);
9334     }
9335   }
9336
9337   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9338   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9339     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9340     aHelper.FixQuadraticElements();
9341   }
9342   if (!GetMeshDS()->isCompacted())
9343     GetMeshDS()->compactMesh();
9344 }
9345
9346 //=======================================================================
9347 /*!
9348  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9349  * \retval int - nb of checked elements
9350  */
9351 //=======================================================================
9352
9353 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9354                                      SMDS_ElemIteratorPtr theItr,
9355                                      const int            theShapeID)
9356 {
9357   int nbElem = 0;
9358   SMESHDS_Mesh* meshDS = GetMeshDS();
9359   const bool notFromGroups = false;
9360
9361   while( theItr->more() )
9362   {
9363     const SMDS_MeshElement* elem = theItr->next();
9364     nbElem++;
9365     if( elem && elem->IsQuadratic())
9366     {
9367       int id = elem->GetID();
9368       int nbNodes = elem->NbNodes();
9369       vector<const SMDS_MeshNode *> nodes, mediumNodes;
9370       nodes.reserve( nbNodes );
9371       mediumNodes.reserve( nbNodes );
9372
9373       for(int i = 0; i < nbNodes; i++)
9374       {
9375         const SMDS_MeshNode* n = elem->GetNode(i);
9376
9377         if( elem->IsMediumNode( n ) )
9378           mediumNodes.push_back( n );
9379         else
9380           nodes.push_back( n );
9381       }
9382       if( nodes.empty() ) continue;
9383       SMDSAbs_ElementType aType = elem->GetType();
9384
9385       //remove old quadratic element
9386       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9387
9388       SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
9389       ReplaceElemInGroups(elem, NewElem, meshDS);
9390       if( theSm && NewElem )
9391         theSm->AddElement( NewElem );
9392
9393       // remove medium nodes
9394       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9395       for ( ; nIt != mediumNodes.end(); ++nIt ) {
9396         const SMDS_MeshNode* n = *nIt;
9397         if ( n->NbInverseElements() == 0 ) {
9398           if ( n->getshapeId() != theShapeID )
9399             meshDS->RemoveFreeNode( n, meshDS->MeshElements
9400                                     ( n->getshapeId() ));
9401           else
9402             meshDS->RemoveFreeNode( n, theSm );
9403         }
9404       }
9405     }
9406   }
9407   return nbElem;
9408 }
9409
9410 //=======================================================================
9411 //function : ConvertFromQuadratic
9412 //purpose  :
9413 //=======================================================================
9414 bool  SMESH_MeshEditor::ConvertFromQuadratic()
9415 {
9416   int nbCheckedElems = 0;
9417   if ( myMesh->HasShapeToMesh() )
9418   {
9419     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9420     {
9421       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9422       while ( smIt->more() ) {
9423         SMESH_subMesh* sm = smIt->next();
9424         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9425           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9426       }
9427     }
9428   }
9429
9430   int totalNbElems =
9431     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9432   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9433   {
9434     SMESHDS_SubMesh *aSM = 0;
9435     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9436   }
9437
9438   return true;
9439 }
9440
9441 //=======================================================================
9442 //function : SewSideElements
9443 //purpose  :
9444 //=======================================================================
9445
9446 SMESH_MeshEditor::Sew_Error
9447 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9448                                    TIDSortedElemSet&    theSide2,
9449                                    const SMDS_MeshNode* theFirstNode1,
9450                                    const SMDS_MeshNode* theFirstNode2,
9451                                    const SMDS_MeshNode* theSecondNode1,
9452                                    const SMDS_MeshNode* theSecondNode2)
9453 {
9454   myLastCreatedElems.Clear();
9455   myLastCreatedNodes.Clear();
9456
9457   MESSAGE ("::::SewSideElements()");
9458   if ( theSide1.size() != theSide2.size() )
9459     return SEW_DIFF_NB_OF_ELEMENTS;
9460
9461   Sew_Error aResult = SEW_OK;
9462   // Algo:
9463   // 1. Build set of faces representing each side
9464   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9465   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9466
9467   // =======================================================================
9468   // 1. Build set of faces representing each side:
9469   // =======================================================================
9470   // a. build set of nodes belonging to faces
9471   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9472   // c. create temporary faces representing side of volumes if correspondent
9473   //    face does not exist
9474
9475   SMESHDS_Mesh* aMesh = GetMeshDS();
9476   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9477   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9478   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9479   set<const SMDS_MeshElement*> volSet1,  volSet2;
9480   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9481   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9482   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9483   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9484   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9485   int iSide, iFace, iNode;
9486
9487   list<const SMDS_MeshElement* > tempFaceList;
9488   for ( iSide = 0; iSide < 2; iSide++ ) {
9489     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9490     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9491     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9492     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9493     set<const SMDS_MeshElement*>::iterator vIt;
9494     TIDSortedElemSet::iterator eIt;
9495     set<const SMDS_MeshNode*>::iterator    nIt;
9496
9497     // check that given nodes belong to given elements
9498     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9499     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9500     int firstIndex = -1, secondIndex = -1;
9501     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9502       const SMDS_MeshElement* elem = *eIt;
9503       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9504       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9505       if ( firstIndex > -1 && secondIndex > -1 ) break;
9506     }
9507     if ( firstIndex < 0 || secondIndex < 0 ) {
9508       // we can simply return until temporary faces created
9509       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9510     }
9511
9512     // -----------------------------------------------------------
9513     // 1a. Collect nodes of existing faces
9514     //     and build set of face nodes in order to detect missing
9515     //     faces corresponding to sides of volumes
9516     // -----------------------------------------------------------
9517
9518     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9519
9520     // loop on the given element of a side
9521     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9522       //const SMDS_MeshElement* elem = *eIt;
9523       const SMDS_MeshElement* elem = *eIt;
9524       if ( elem->GetType() == SMDSAbs_Face ) {
9525         faceSet->insert( elem );
9526         set <const SMDS_MeshNode*> faceNodeSet;
9527         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9528         while ( nodeIt->more() ) {
9529           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9530           nodeSet->insert( n );
9531           faceNodeSet.insert( n );
9532         }
9533         setOfFaceNodeSet.insert( faceNodeSet );
9534       }
9535       else if ( elem->GetType() == SMDSAbs_Volume )
9536         volSet->insert( elem );
9537     }
9538     // ------------------------------------------------------------------------------
9539     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9540     // ------------------------------------------------------------------------------
9541
9542     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9543       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9544       while ( fIt->more() ) { // loop on faces sharing a node
9545         const SMDS_MeshElement* f = fIt->next();
9546         if ( faceSet->find( f ) == faceSet->end() ) {
9547           // check if all nodes are in nodeSet and
9548           // complete setOfFaceNodeSet if they are
9549           set <const SMDS_MeshNode*> faceNodeSet;
9550           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9551           bool allInSet = true;
9552           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9553             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9554             if ( nodeSet->find( n ) == nodeSet->end() )
9555               allInSet = false;
9556             else
9557               faceNodeSet.insert( n );
9558           }
9559           if ( allInSet ) {
9560             faceSet->insert( f );
9561             setOfFaceNodeSet.insert( faceNodeSet );
9562           }
9563         }
9564       }
9565     }
9566
9567     // -------------------------------------------------------------------------
9568     // 1c. Create temporary faces representing sides of volumes if correspondent
9569     //     face does not exist
9570     // -------------------------------------------------------------------------
9571
9572     if ( !volSet->empty() ) {
9573       //int nodeSetSize = nodeSet->size();
9574
9575       // loop on given volumes
9576       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9577         SMDS_VolumeTool vol (*vIt);
9578         // loop on volume faces: find free faces
9579         // --------------------------------------
9580         list<const SMDS_MeshElement* > freeFaceList;
9581         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9582           if ( !vol.IsFreeFace( iFace ))
9583             continue;
9584           // check if there is already a face with same nodes in a face set
9585           const SMDS_MeshElement* aFreeFace = 0;
9586           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9587           int nbNodes = vol.NbFaceNodes( iFace );
9588           set <const SMDS_MeshNode*> faceNodeSet;
9589           vol.GetFaceNodes( iFace, faceNodeSet );
9590           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9591           if ( isNewFace ) {
9592             // no such a face is given but it still can exist, check it
9593             if ( nbNodes == 3 ) {
9594               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9595             }
9596             else if ( nbNodes == 4 ) {
9597               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9598             }
9599             else {
9600               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9601               aFreeFace = aMesh->FindFace(poly_nodes);
9602             }
9603           }
9604           if ( !aFreeFace ) {
9605             // create a temporary face
9606             if ( nbNodes == 3 ) {
9607               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9608               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9609             }
9610             else if ( nbNodes == 4 ) {
9611               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9612               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9613             }
9614             else {
9615               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9616               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9617               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9618             }
9619           }
9620           if ( aFreeFace ) {
9621             freeFaceList.push_back( aFreeFace );
9622             tempFaceList.push_back( aFreeFace );
9623           }
9624
9625         } // loop on faces of a volume
9626
9627         // choose one of several free faces
9628         // --------------------------------------
9629         if ( freeFaceList.size() > 1 ) {
9630           // choose a face having max nb of nodes shared by other elems of a side
9631           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9632           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9633           while ( fIt != freeFaceList.end() ) { // loop on free faces
9634             int nbSharedNodes = 0;
9635             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9636             while ( nodeIt->more() ) { // loop on free face nodes
9637               const SMDS_MeshNode* n =
9638                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9639               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9640               while ( invElemIt->more() ) {
9641                 const SMDS_MeshElement* e = invElemIt->next();
9642                 if ( faceSet->find( e ) != faceSet->end() )
9643                   nbSharedNodes++;
9644                 if ( elemSet->find( e ) != elemSet->end() )
9645                   nbSharedNodes++;
9646               }
9647             }
9648             if ( nbSharedNodes >= maxNbNodes ) {
9649               maxNbNodes = nbSharedNodes;
9650               fIt++;
9651             }
9652             else
9653               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9654           }
9655           if ( freeFaceList.size() > 1 )
9656           {
9657             // could not choose one face, use another way
9658             // choose a face most close to the bary center of the opposite side
9659             gp_XYZ aBC( 0., 0., 0. );
9660             set <const SMDS_MeshNode*> addedNodes;
9661             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9662             eIt = elemSet2->begin();
9663             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9664               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9665               while ( nodeIt->more() ) { // loop on free face nodes
9666                 const SMDS_MeshNode* n =
9667                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9668                 if ( addedNodes.insert( n ).second )
9669                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9670               }
9671             }
9672             aBC /= addedNodes.size();
9673             double minDist = DBL_MAX;
9674             fIt = freeFaceList.begin();
9675             while ( fIt != freeFaceList.end() ) { // loop on free faces
9676               double dist = 0;
9677               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9678               while ( nodeIt->more() ) { // loop on free face nodes
9679                 const SMDS_MeshNode* n =
9680                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9681                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9682                 dist += ( aBC - p ).SquareModulus();
9683               }
9684               if ( dist < minDist ) {
9685                 minDist = dist;
9686                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9687               }
9688               else
9689                 fIt = freeFaceList.erase( fIt++ );
9690             }
9691           }
9692         } // choose one of several free faces of a volume
9693
9694         if ( freeFaceList.size() == 1 ) {
9695           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9696           faceSet->insert( aFreeFace );
9697           // complete a node set with nodes of a found free face
9698           //           for ( iNode = 0; iNode < ; iNode++ )
9699           //             nodeSet->insert( fNodes[ iNode ] );
9700         }
9701
9702       } // loop on volumes of a side
9703
9704       //       // complete a set of faces if new nodes in a nodeSet appeared
9705       //       // ----------------------------------------------------------
9706       //       if ( nodeSetSize != nodeSet->size() ) {
9707       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9708       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9709       //           while ( fIt->more() ) { // loop on faces sharing a node
9710       //             const SMDS_MeshElement* f = fIt->next();
9711       //             if ( faceSet->find( f ) == faceSet->end() ) {
9712       //               // check if all nodes are in nodeSet and
9713       //               // complete setOfFaceNodeSet if they are
9714       //               set <const SMDS_MeshNode*> faceNodeSet;
9715       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9716       //               bool allInSet = true;
9717       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9718       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9719       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9720       //                   allInSet = false;
9721       //                 else
9722       //                   faceNodeSet.insert( n );
9723       //               }
9724       //               if ( allInSet ) {
9725       //                 faceSet->insert( f );
9726       //                 setOfFaceNodeSet.insert( faceNodeSet );
9727       //               }
9728       //             }
9729       //           }
9730       //         }
9731       //       }
9732     } // Create temporary faces, if there are volumes given
9733   } // loop on sides
9734
9735   if ( faceSet1.size() != faceSet2.size() ) {
9736     // delete temporary faces: they are in reverseElements of actual nodes
9737 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9738 //    while ( tmpFaceIt->more() )
9739 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9740 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9741 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9742 //      aMesh->RemoveElement(*tmpFaceIt);
9743     MESSAGE("Diff nb of faces");
9744     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9745   }
9746
9747   // ============================================================
9748   // 2. Find nodes to merge:
9749   //              bind a node to remove to a node to put instead
9750   // ============================================================
9751
9752   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9753   if ( theFirstNode1 != theFirstNode2 )
9754     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9755   if ( theSecondNode1 != theSecondNode2 )
9756     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9757
9758   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9759   set< long > linkIdSet; // links to process
9760   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9761
9762   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9763   list< NLink > linkList[2];
9764   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9765   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9766   // loop on links in linkList; find faces by links and append links
9767   // of the found faces to linkList
9768   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9769   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9770     NLink link[] = { *linkIt[0], *linkIt[1] };
9771     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9772     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9773       continue;
9774
9775     // by links, find faces in the face sets,
9776     // and find indices of link nodes in the found faces;
9777     // in a face set, there is only one or no face sharing a link
9778     // ---------------------------------------------------------------
9779
9780     const SMDS_MeshElement* face[] = { 0, 0 };
9781     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9782     vector<const SMDS_MeshNode*> fnodes1(9);
9783     vector<const SMDS_MeshNode*> fnodes2(9);
9784     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9785     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9786     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9787     int iLinkNode[2][2];
9788     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9789       const SMDS_MeshNode* n1 = link[iSide].first;
9790       const SMDS_MeshNode* n2 = link[iSide].second;
9791       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9792       set< const SMDS_MeshElement* > fMap;
9793       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9794         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9795         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9796         while ( fIt->more() ) { // loop on faces sharing a node
9797           const SMDS_MeshElement* f = fIt->next();
9798           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9799               ! fMap.insert( f ).second ) // f encounters twice
9800           {
9801             if ( face[ iSide ] ) {
9802               MESSAGE( "2 faces per link " );
9803               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9804               break;
9805             }
9806             face[ iSide ] = f;
9807             faceSet->erase( f );
9808             // get face nodes and find ones of a link
9809             iNode = 0;
9810             int nbl = -1;
9811             if(f->IsPoly()) {
9812               if(iSide==0) {
9813                 fnodes1.resize(f->NbNodes()+1);
9814                 notLinkNodes1.resize(f->NbNodes()-2);
9815               }
9816               else {
9817                 fnodes2.resize(f->NbNodes()+1);
9818                 notLinkNodes2.resize(f->NbNodes()-2);
9819               }
9820             }
9821             if(!f->IsQuadratic()) {
9822               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9823               while ( nIt->more() ) {
9824                 const SMDS_MeshNode* n =
9825                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9826                 if ( n == n1 ) {
9827                   iLinkNode[ iSide ][ 0 ] = iNode;
9828                 }
9829                 else if ( n == n2 ) {
9830                   iLinkNode[ iSide ][ 1 ] = iNode;
9831                 }
9832                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9833                 //  notLinkNodes[ iSide ][ 1 ] = n;
9834                 //else
9835                 //  notLinkNodes[ iSide ][ 0 ] = n;
9836                 else {
9837                   nbl++;
9838                   if(iSide==0)
9839                     notLinkNodes1[nbl] = n;
9840                   //notLinkNodes1.push_back(n);
9841                   else
9842                     notLinkNodes2[nbl] = n;
9843                   //notLinkNodes2.push_back(n);
9844                 }
9845                 //faceNodes[ iSide ][ iNode++ ] = n;
9846                 if(iSide==0) {
9847                   fnodes1[iNode++] = n;
9848                 }
9849                 else {
9850                   fnodes2[iNode++] = n;
9851                 }
9852               }
9853             }
9854             else { // f->IsQuadratic()
9855               const SMDS_VtkFace* F =
9856                 dynamic_cast<const SMDS_VtkFace*>(f);
9857               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9858               // use special nodes iterator
9859               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9860               while ( anIter->more() ) {
9861                 const SMDS_MeshNode* n =
9862                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9863                 if ( n == n1 ) {
9864                   iLinkNode[ iSide ][ 0 ] = iNode;
9865                 }
9866                 else if ( n == n2 ) {
9867                   iLinkNode[ iSide ][ 1 ] = iNode;
9868                 }
9869                 else {
9870                   nbl++;
9871                   if(iSide==0) {
9872                     notLinkNodes1[nbl] = n;
9873                   }
9874                   else {
9875                     notLinkNodes2[nbl] = n;
9876                   }
9877                 }
9878                 if(iSide==0) {
9879                   fnodes1[iNode++] = n;
9880                 }
9881                 else {
9882                   fnodes2[iNode++] = n;
9883                 }
9884               }
9885             }
9886             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9887             if(iSide==0) {
9888               fnodes1[iNode] = fnodes1[0];
9889             }
9890             else {
9891               fnodes2[iNode] = fnodes1[0];
9892             }
9893           }
9894         }
9895       }
9896     }
9897
9898     // check similarity of elements of the sides
9899     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9900       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9901       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9902         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9903       }
9904       else {
9905         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9906       }
9907       break; // do not return because it s necessary to remove tmp faces
9908     }
9909
9910     // set nodes to merge
9911     // -------------------
9912
9913     if ( face[0] && face[1] )  {
9914       int nbNodes = face[0]->NbNodes();
9915       if ( nbNodes != face[1]->NbNodes() ) {
9916         MESSAGE("Diff nb of face nodes");
9917         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9918         break; // do not return because it s necessary to remove tmp faces
9919       }
9920       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9921       if ( nbNodes == 3 ) {
9922         //nReplaceMap.insert( TNodeNodeMap::value_type
9923         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9924         nReplaceMap.insert( TNodeNodeMap::value_type
9925                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9926       }
9927       else {
9928         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9929           // analyse link orientation in faces
9930           int i1 = iLinkNode[ iSide ][ 0 ];
9931           int i2 = iLinkNode[ iSide ][ 1 ];
9932           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9933           // if notLinkNodes are the first and the last ones, then
9934           // their order does not correspond to the link orientation
9935           if (( i1 == 1 && i2 == 2 ) ||
9936               ( i1 == 2 && i2 == 1 ))
9937             reverse[ iSide ] = !reverse[ iSide ];
9938         }
9939         if ( reverse[0] == reverse[1] ) {
9940           //nReplaceMap.insert( TNodeNodeMap::value_type
9941           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9942           //nReplaceMap.insert( TNodeNodeMap::value_type
9943           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9944           for(int nn=0; nn<nbNodes-2; nn++) {
9945             nReplaceMap.insert( TNodeNodeMap::value_type
9946                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9947           }
9948         }
9949         else {
9950           //nReplaceMap.insert( TNodeNodeMap::value_type
9951           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9952           //nReplaceMap.insert( TNodeNodeMap::value_type
9953           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9954           for(int nn=0; nn<nbNodes-2; nn++) {
9955             nReplaceMap.insert( TNodeNodeMap::value_type
9956                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9957           }
9958         }
9959       }
9960
9961       // add other links of the faces to linkList
9962       // -----------------------------------------
9963
9964       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9965       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9966         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9967         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9968         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9969         if ( !iter_isnew.second ) { // already in a set: no need to process
9970           linkIdSet.erase( iter_isnew.first );
9971         }
9972         else // new in set == encountered for the first time: add
9973         {
9974           //const SMDS_MeshNode* n1 = nodes[ iNode ];
9975           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9976           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9977           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9978           linkList[0].push_back ( NLink( n1, n2 ));
9979           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9980         }
9981       }
9982     } // 2 faces found
9983   } // loop on link lists
9984
9985   if ( aResult == SEW_OK &&
9986        ( linkIt[0] != linkList[0].end() ||
9987          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9988     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9989              " " << (faceSetPtr[1]->empty()));
9990     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9991   }
9992
9993   // ====================================================================
9994   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9995   // ====================================================================
9996
9997   // delete temporary faces: they are in reverseElements of actual nodes
9998 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9999 //  while ( tmpFaceIt->more() )
10000 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10001 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10002 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10003 //    aMesh->RemoveElement(*tmpFaceIt);
10004
10005   if ( aResult != SEW_OK)
10006     return aResult;
10007
10008   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10009   // loop on nodes replacement map
10010   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10011   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10012     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10013       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10014       nodeIDsToRemove.push_back( nToRemove->GetID() );
10015       // loop on elements sharing nToRemove
10016       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10017       while ( invElemIt->more() ) {
10018         const SMDS_MeshElement* e = invElemIt->next();
10019         // get a new suite of nodes: make replacement
10020         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10021         vector< const SMDS_MeshNode*> nodes( nbNodes );
10022         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10023         while ( nIt->more() ) {
10024           const SMDS_MeshNode* n =
10025             static_cast<const SMDS_MeshNode*>( nIt->next() );
10026           nnIt = nReplaceMap.find( n );
10027           if ( nnIt != nReplaceMap.end() ) {
10028             nbReplaced++;
10029             n = (*nnIt).second;
10030           }
10031           nodes[ i++ ] = n;
10032         }
10033         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10034         //         elemIDsToRemove.push_back( e->GetID() );
10035         //       else
10036         if ( nbReplaced )
10037           {
10038             SMDSAbs_ElementType etyp = e->GetType();
10039             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10040             if (newElem)
10041               {
10042                 myLastCreatedElems.Append(newElem);
10043                 AddToSameGroups(newElem, e, aMesh);
10044                 int aShapeId = e->getshapeId();
10045                 if ( aShapeId )
10046                   {
10047                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10048                   }
10049               }
10050             aMesh->RemoveElement(e);
10051           }
10052       }
10053     }
10054
10055   Remove( nodeIDsToRemove, true );
10056
10057   return aResult;
10058 }
10059
10060 //================================================================================
10061 /*!
10062  * \brief Find corresponding nodes in two sets of faces
10063  * \param theSide1 - first face set
10064  * \param theSide2 - second first face
10065  * \param theFirstNode1 - a boundary node of set 1
10066  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10067  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10068  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10069  * \param nReplaceMap - output map of corresponding nodes
10070  * \retval bool  - is a success or not
10071  */
10072 //================================================================================
10073
10074 #ifdef _DEBUG_
10075 //#define DEBUG_MATCHING_NODES
10076 #endif
10077
10078 SMESH_MeshEditor::Sew_Error
10079 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10080                                     set<const SMDS_MeshElement*>& theSide2,
10081                                     const SMDS_MeshNode*          theFirstNode1,
10082                                     const SMDS_MeshNode*          theFirstNode2,
10083                                     const SMDS_MeshNode*          theSecondNode1,
10084                                     const SMDS_MeshNode*          theSecondNode2,
10085                                     TNodeNodeMap &                nReplaceMap)
10086 {
10087   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10088
10089   nReplaceMap.clear();
10090   if ( theFirstNode1 != theFirstNode2 )
10091     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10092   if ( theSecondNode1 != theSecondNode2 )
10093     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10094
10095   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10096   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10097
10098   list< NLink > linkList[2];
10099   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10100   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10101
10102   // loop on links in linkList; find faces by links and append links
10103   // of the found faces to linkList
10104   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10105   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10106     NLink link[] = { *linkIt[0], *linkIt[1] };
10107     if ( linkSet.find( link[0] ) == linkSet.end() )
10108       continue;
10109
10110     // by links, find faces in the face sets,
10111     // and find indices of link nodes in the found faces;
10112     // in a face set, there is only one or no face sharing a link
10113     // ---------------------------------------------------------------
10114
10115     const SMDS_MeshElement* face[] = { 0, 0 };
10116     list<const SMDS_MeshNode*> notLinkNodes[2];
10117     //bool reverse[] = { false, false }; // order of notLinkNodes
10118     int nbNodes[2];
10119     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10120     {
10121       const SMDS_MeshNode* n1 = link[iSide].first;
10122       const SMDS_MeshNode* n2 = link[iSide].second;
10123       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10124       set< const SMDS_MeshElement* > facesOfNode1;
10125       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10126       {
10127         // during a loop of the first node, we find all faces around n1,
10128         // during a loop of the second node, we find one face sharing both n1 and n2
10129         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10130         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10131         while ( fIt->more() ) { // loop on faces sharing a node
10132           const SMDS_MeshElement* f = fIt->next();
10133           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10134               ! facesOfNode1.insert( f ).second ) // f encounters twice
10135           {
10136             if ( face[ iSide ] ) {
10137               MESSAGE( "2 faces per link " );
10138               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10139             }
10140             face[ iSide ] = f;
10141             faceSet->erase( f );
10142
10143             // get not link nodes
10144             int nbN = f->NbNodes();
10145             if ( f->IsQuadratic() )
10146               nbN /= 2;
10147             nbNodes[ iSide ] = nbN;
10148             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10149             int i1 = f->GetNodeIndex( n1 );
10150             int i2 = f->GetNodeIndex( n2 );
10151             int iEnd = nbN, iBeg = -1, iDelta = 1;
10152             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10153             if ( reverse ) {
10154               std::swap( iEnd, iBeg ); iDelta = -1;
10155             }
10156             int i = i2;
10157             while ( true ) {
10158               i += iDelta;
10159               if ( i == iEnd ) i = iBeg + iDelta;
10160               if ( i == i1 ) break;
10161               nodes.push_back ( f->GetNode( i ) );
10162             }
10163           }
10164         }
10165       }
10166     }
10167     // check similarity of elements of the sides
10168     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10169       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10170       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10171         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10172       }
10173       else {
10174         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10175       }
10176     }
10177
10178     // set nodes to merge
10179     // -------------------
10180
10181     if ( face[0] && face[1] )  {
10182       if ( nbNodes[0] != nbNodes[1] ) {
10183         MESSAGE("Diff nb of face nodes");
10184         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10185       }
10186 #ifdef DEBUG_MATCHING_NODES
10187       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10188                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10189                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10190 #endif
10191       int nbN = nbNodes[0];
10192       {
10193         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10194         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10195         for ( int i = 0 ; i < nbN - 2; ++i ) {
10196 #ifdef DEBUG_MATCHING_NODES
10197           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10198 #endif
10199           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10200         }
10201       }
10202
10203       // add other links of the face 1 to linkList
10204       // -----------------------------------------
10205
10206       const SMDS_MeshElement* f0 = face[0];
10207       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10208       for ( int i = 0; i < nbN; i++ )
10209       {
10210         const SMDS_MeshNode* n2 = f0->GetNode( i );
10211         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10212           linkSet.insert( SMESH_TLink( n1, n2 ));
10213         if ( !iter_isnew.second ) { // already in a set: no need to process
10214           linkSet.erase( iter_isnew.first );
10215         }
10216         else // new in set == encountered for the first time: add
10217         {
10218 #ifdef DEBUG_MATCHING_NODES
10219           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10220                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10221 #endif
10222           linkList[0].push_back ( NLink( n1, n2 ));
10223           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10224         }
10225         n1 = n2;
10226       }
10227     } // 2 faces found
10228   } // loop on link lists
10229
10230   return SEW_OK;
10231 }
10232
10233 //================================================================================
10234 /*!
10235   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10236   \param theElems - the list of elements (edges or faces) to be replicated
10237   The nodes for duplication could be found from these elements
10238   \param theNodesNot - list of nodes to NOT replicate
10239   \param theAffectedElems - the list of elements (cells and edges) to which the 
10240   replicated nodes should be associated to.
10241   \return TRUE if operation has been completed successfully, FALSE otherwise
10242 */
10243 //================================================================================
10244
10245 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10246                                     const TIDSortedElemSet& theNodesNot,
10247                                     const TIDSortedElemSet& theAffectedElems )
10248 {
10249   myLastCreatedElems.Clear();
10250   myLastCreatedNodes.Clear();
10251
10252   if ( theElems.size() == 0 )
10253     return false;
10254
10255   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10256   if ( !aMeshDS )
10257     return false;
10258
10259   bool res = false;
10260   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10261   // duplicate elements and nodes
10262   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10263   // replce nodes by duplications
10264   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10265   return res;
10266 }
10267
10268 //================================================================================
10269 /*!
10270   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10271   \param theMeshDS - mesh instance
10272   \param theElems - the elements replicated or modified (nodes should be changed)
10273   \param theNodesNot - nodes to NOT replicate
10274   \param theNodeNodeMap - relation of old node to new created node
10275   \param theIsDoubleElem - flag os to replicate element or modify
10276   \return TRUE if operation has been completed successfully, FALSE otherwise
10277 */
10278 //================================================================================
10279
10280 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10281                                     const TIDSortedElemSet& theElems,
10282                                     const TIDSortedElemSet& theNodesNot,
10283                                     std::map< const SMDS_MeshNode*,
10284                                     const SMDS_MeshNode* >& theNodeNodeMap,
10285                                     const bool theIsDoubleElem )
10286 {
10287   MESSAGE("doubleNodes");
10288   // iterate on through element and duplicate them (by nodes duplication)
10289   bool res = false;
10290   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10291   for ( ;  elemItr != theElems.end(); ++elemItr )
10292   {
10293     const SMDS_MeshElement* anElem = *elemItr;
10294     if (!anElem)
10295       continue;
10296
10297     bool isDuplicate = false;
10298     // duplicate nodes to duplicate element
10299     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10300     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10301     int ind = 0;
10302     while ( anIter->more() ) 
10303     { 
10304
10305       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10306       SMDS_MeshNode* aNewNode = aCurrNode;
10307       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10308         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10309       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10310       {
10311         // duplicate node
10312         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10313         theNodeNodeMap[ aCurrNode ] = aNewNode;
10314         myLastCreatedNodes.Append( aNewNode );
10315       }
10316       isDuplicate |= (aCurrNode != aNewNode);
10317       newNodes[ ind++ ] = aNewNode;
10318     }
10319     if ( !isDuplicate )
10320       continue;
10321
10322     if ( theIsDoubleElem )
10323       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10324     else
10325       {
10326       MESSAGE("ChangeElementNodes");
10327       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10328       }
10329     res = true;
10330   }
10331   return res;
10332 }
10333
10334 //================================================================================
10335 /*!
10336   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10337   \param theNodes - identifiers of nodes to be doubled
10338   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10339          nodes. If list of element identifiers is empty then nodes are doubled but 
10340          they not assigned to elements
10341   \return TRUE if operation has been completed successfully, FALSE otherwise
10342 */
10343 //================================================================================
10344
10345 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10346                                     const std::list< int >& theListOfModifiedElems )
10347 {
10348   MESSAGE("DoubleNodes");
10349   myLastCreatedElems.Clear();
10350   myLastCreatedNodes.Clear();
10351
10352   if ( theListOfNodes.size() == 0 )
10353     return false;
10354
10355   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10356   if ( !aMeshDS )
10357     return false;
10358
10359   // iterate through nodes and duplicate them
10360
10361   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10362
10363   std::list< int >::const_iterator aNodeIter;
10364   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10365   {
10366     int aCurr = *aNodeIter;
10367     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10368     if ( !aNode )
10369       continue;
10370
10371     // duplicate node
10372
10373     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10374     if ( aNewNode )
10375     {
10376       anOldNodeToNewNode[ aNode ] = aNewNode;
10377       myLastCreatedNodes.Append( aNewNode );
10378     }
10379   }
10380
10381   // Create map of new nodes for modified elements
10382
10383   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10384
10385   std::list< int >::const_iterator anElemIter;
10386   for ( anElemIter = theListOfModifiedElems.begin(); 
10387         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10388   {
10389     int aCurr = *anElemIter;
10390     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10391     if ( !anElem )
10392       continue;
10393
10394     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10395
10396     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10397     int ind = 0;
10398     while ( anIter->more() ) 
10399     { 
10400       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10401       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10402       {
10403         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10404         aNodeArr[ ind++ ] = aNewNode;
10405       }
10406       else
10407         aNodeArr[ ind++ ] = aCurrNode;
10408     }
10409     anElemToNodes[ anElem ] = aNodeArr;
10410   }
10411
10412   // Change nodes of elements  
10413
10414   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10415     anElemToNodesIter = anElemToNodes.begin();
10416   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10417   {
10418     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10419     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10420     if ( anElem )
10421       {
10422       MESSAGE("ChangeElementNodes");
10423       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10424       }
10425   }
10426
10427   return true;
10428 }
10429
10430 namespace {
10431
10432   //================================================================================
10433   /*!
10434   \brief Check if element located inside shape
10435   \return TRUE if IN or ON shape, FALSE otherwise
10436   */
10437   //================================================================================
10438
10439   template<class Classifier>
10440   bool isInside(const SMDS_MeshElement* theElem,
10441                 Classifier&             theClassifier,
10442                 const double            theTol)
10443   {
10444     gp_XYZ centerXYZ (0, 0, 0);
10445     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10446     while (aNodeItr->more())
10447       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10448
10449     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10450     theClassifier.Perform(aPnt, theTol);
10451     TopAbs_State aState = theClassifier.State();
10452     return (aState == TopAbs_IN || aState == TopAbs_ON );
10453   }
10454
10455   //================================================================================
10456   /*!
10457    * \brief Classifier of the 3D point on the TopoDS_Face
10458    *        with interaface suitable for isInside()
10459    */
10460   //================================================================================
10461
10462   struct _FaceClassifier
10463   {
10464     Extrema_ExtPS       _extremum;
10465     BRepAdaptor_Surface _surface;
10466     TopAbs_State        _state;
10467
10468     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10469     {
10470       _extremum.Initialize( _surface,
10471                             _surface.FirstUParameter(), _surface.LastUParameter(),
10472                             _surface.FirstVParameter(), _surface.LastVParameter(),
10473                             _surface.Tolerance(), _surface.Tolerance() );
10474     }
10475     void Perform(const gp_Pnt& aPnt, double theTol)
10476     {
10477       _state = TopAbs_OUT;
10478       _extremum.Perform(aPnt);
10479       if ( _extremum.IsDone() )
10480         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10481           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10482     }
10483     TopAbs_State State() const
10484     {
10485       return _state;
10486     }
10487   };
10488 }
10489
10490 //================================================================================
10491 /*!
10492   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10493   \param theElems - group of of elements (edges or faces) to be replicated
10494   \param theNodesNot - group of nodes not to replicate
10495   \param theShape - shape to detect affected elements (element which geometric center
10496   located on or inside shape).
10497   The replicated nodes should be associated to affected elements.
10498   \return TRUE if operation has been completed successfully, FALSE otherwise
10499 */
10500 //================================================================================
10501
10502 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10503                                             const TIDSortedElemSet& theNodesNot,
10504                                             const TopoDS_Shape&     theShape )
10505 {
10506   if ( theShape.IsNull() )
10507     return false;
10508
10509   const double aTol = Precision::Confusion();
10510   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10511   auto_ptr<_FaceClassifier>              aFaceClassifier;
10512   if ( theShape.ShapeType() == TopAbs_SOLID )
10513   {
10514     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10515     bsc3d->PerformInfinitePoint(aTol);
10516   }
10517   else if (theShape.ShapeType() == TopAbs_FACE )
10518   {
10519     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10520   }
10521
10522   // iterates on indicated elements and get elements by back references from their nodes
10523   TIDSortedElemSet anAffected;
10524   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10525   for ( ;  elemItr != theElems.end(); ++elemItr )
10526   {
10527     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10528     if (!anElem)
10529       continue;
10530
10531     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10532     while ( nodeItr->more() )
10533     {
10534       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10535       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10536         continue;
10537       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10538       while ( backElemItr->more() )
10539       {
10540         const SMDS_MeshElement* curElem = backElemItr->next();
10541         if ( curElem && theElems.find(curElem) == theElems.end() &&
10542              ( bsc3d.get() ?
10543                isInside( curElem, *bsc3d, aTol ) :
10544                isInside( curElem, *aFaceClassifier, aTol )))
10545           anAffected.insert( curElem );
10546       }
10547     }
10548   }
10549   return DoubleNodes( theElems, theNodesNot, anAffected );
10550 }
10551
10552 /*!
10553  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10554  * The list of groups must describe a partition of the mesh volumes.
10555  * The nodes of the internal faces at the boundaries of the groups are doubled.
10556  * In option, the internal faces are replaced by flat elements.
10557  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10558  * @param theElems - list of groups of volumes, where a group of volume is a set of
10559  * SMDS_MeshElements sorted by Id.
10560  * @param createJointElems - if TRUE, create the elements
10561  * @return TRUE if operation has been completed successfully, FALSE otherwise
10562  */
10563 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10564                                                      bool createJointElems)
10565 {
10566   MESSAGE("------------------------------------------------------");
10567   MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
10568   MESSAGE("------------------------------------------------------");
10569
10570   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10571   meshDS->BuildDownWardConnectivity(false);
10572   CHRONO(50);
10573   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10574
10575   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10576   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10577
10578   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
10579   std::map<int, std::map<int,int> > nodeDomains; //oldId ->  (domainId -> newId)
10580   faceDomains.clear();
10581   nodeDomains.clear();
10582   std::map<int,int> emptyMap;
10583   emptyMap.clear();
10584
10585   for (int idom = 0; idom < theElems.size(); idom++)
10586     {
10587
10588       // --- build a map (face to duplicate --> volume to modify)
10589       //     with all the faces shared by 2 domains (group of elements)
10590       //     and corresponding volume of this domain, for each shared face.
10591       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10592
10593       const TIDSortedElemSet& domain = theElems[idom];
10594       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10595       for (; elemItr != domain.end(); ++elemItr)
10596         {
10597           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10598           if (!anElem)
10599             continue;
10600           int vtkId = anElem->getVtkId();
10601           int neighborsVtkIds[NBMAXNEIGHBORS];
10602           int downIds[NBMAXNEIGHBORS];
10603           unsigned char downTypes[NBMAXNEIGHBORS];
10604           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10605           for (int n = 0; n < nbNeighbors; n++)
10606             {
10607               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10608               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10609               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10610                 {
10611                   DownIdType face(downIds[n], downTypes[n]);
10612                   if (!faceDomains.count(face))
10613                     faceDomains[face] = emptyMap; // create an empty entry for face
10614                   if (!faceDomains[face].count(idom))
10615                     {
10616                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10617                     }
10618                 }
10619             }
10620         }
10621     }
10622
10623   MESSAGE("Number of shared faces " << faceDomains.size());
10624
10625   // --- for each shared face, get the nodes
10626   //     for each node, for each domain of the face, create a clone of the node
10627
10628   std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
10629   for( ; itface != faceDomains.end();++itface )
10630     {
10631       DownIdType face = itface->first;
10632       std::map<int,int> domvol = itface->second;
10633       std::set<int> oldNodes;
10634       oldNodes.clear();
10635       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10636       std::set<int>::iterator itn = oldNodes.begin();
10637       for (;itn != oldNodes.end(); ++itn)
10638         {
10639           int oldId = *itn;
10640           if (!nodeDomains.count(oldId))
10641             nodeDomains[oldId] = emptyMap; // create an empty entry for node
10642           std::map<int,int>::iterator itdom = domvol.begin();
10643           for(; itdom != domvol.end(); ++itdom)
10644             {
10645               int idom = itdom->first;
10646               if ( nodeDomains[oldId].empty() )
10647                 nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
10648               else
10649                 {
10650                   double *coords = grid->GetPoint(oldId);
10651                   SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10652                   int newId = newNode->getVtkId();
10653                   nodeDomains[oldId][idom] = newId; // cloned node for other domains
10654                 }
10655             }
10656         }
10657     }
10658
10659   // --- iterate on shared faces (volumes to modify, face to extrude)
10660   //     get node id's of the face (id SMDS = id VTK)
10661   //     create flat element with old and new nodes if requested
10662
10663   if (createJointElems)
10664     {
10665       itface = faceDomains.begin();
10666       for( ; itface != faceDomains.end();++itface )
10667         {
10668           DownIdType face = itface->first;
10669           std::set<int> oldNodes;
10670           std::set<int>::iterator itn;
10671           oldNodes.clear();
10672           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10673           std::map<int,int> localClonedNodeIds;
10674
10675           std::map<int,int> domvol = itface->second;
10676           std::map<int,int>::iterator itdom = domvol.begin();
10677           int dom1 = itdom->first;
10678           int vtkVolId = itdom->second;
10679           itdom++;
10680           int dom2 = itdom->first;
10681
10682           localClonedNodeIds.clear();
10683           for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10684             {
10685               int oldId = *itn;
10686               int refid = oldId;
10687               if (nodeDomains[oldId].count(dom1))
10688                 refid = nodeDomains[oldId][dom1];
10689               else
10690                 MESSAGE("--- problem domain node " << dom1 << " " << oldId);
10691               int newid = oldId;
10692               if (nodeDomains[oldId].count(dom2))
10693                 newid = nodeDomains[oldId][dom2];
10694               else
10695                 MESSAGE("--- problem domain node " << dom2 << " " << oldId);
10696               localClonedNodeIds[oldId] = newid;
10697             }
10698           meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
10699         }
10700     }
10701
10702   // --- iterate on shared faces (volumes to modify, face to extrude)
10703   //     get node id's of the face
10704   //     replace old nodes by new nodes in volumes, and update inverse connectivity
10705
10706   itface = faceDomains.begin();
10707   for( ; itface != faceDomains.end();++itface )
10708     {
10709       DownIdType face = itface->first;
10710       std::set<int> oldNodes;
10711       std::set<int>::iterator itn;
10712       oldNodes.clear();
10713       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10714       std::map<int,int> localClonedNodeIds;
10715
10716       std::map<int,int> domvol = itface->second;
10717       std::map<int,int>::iterator itdom = domvol.begin();
10718       for(; itdom != domvol.end(); ++itdom)
10719         {
10720           int idom = itdom->first;
10721           int vtkVolId = itdom->second;
10722           localClonedNodeIds.clear();
10723           for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10724             {
10725               int oldId = *itn;
10726               if (nodeDomains[oldId].count(idom))
10727                 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10728             }
10729           meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10730         }
10731     }
10732   grid->BuildLinks();
10733
10734   // TODO replace also old nodes by new nodes in faces and edges
10735   CHRONOSTOP(50);
10736   counters::stats();
10737   return true;
10738 }
10739
10740 //================================================================================
10741 /*!
10742  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10743  * The created 2D mesh elements based on nodes of free faces of boundary volumes
10744  * \return TRUE if operation has been completed successfully, FALSE otherwise
10745  */
10746 //================================================================================
10747
10748 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10749 {
10750   // iterates on volume elements and detect all free faces on them
10751   SMESHDS_Mesh* aMesh = GetMeshDS();
10752   if (!aMesh)
10753     return false;
10754   //bool res = false;
10755   int nbFree = 0, nbExisted = 0, nbCreated = 0;
10756   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10757   while(vIt->more())
10758   {
10759     const SMDS_MeshVolume* volume = vIt->next();
10760     SMDS_VolumeTool vTool( volume );
10761     vTool.SetExternalNormal();
10762     const bool isPoly = volume->IsPoly();
10763     const bool isQuad = volume->IsQuadratic();
10764     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10765     {
10766       if (!vTool.IsFreeFace(iface))
10767         continue;
10768       nbFree++;
10769       vector<const SMDS_MeshNode *> nodes;
10770       int nbFaceNodes = vTool.NbFaceNodes(iface);
10771       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10772       int inode = 0;
10773       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10774         nodes.push_back(faceNodes[inode]);
10775       if (isQuad)
10776         for ( inode = 1; inode < nbFaceNodes; inode += 2)
10777           nodes.push_back(faceNodes[inode]);
10778
10779       // add new face based on volume nodes
10780       if (aMesh->FindFace( nodes ) ) {
10781         nbExisted++;
10782         continue; // face already exsist
10783       }
10784       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10785       nbCreated++;
10786     }
10787   }
10788   return ( nbFree==(nbExisted+nbCreated) );
10789 }
10790
10791 namespace
10792 {
10793   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10794   {
10795     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10796       return n;
10797     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10798   }
10799 }
10800 //================================================================================
10801 /*!
10802  * \brief Creates missing boundary elements
10803  *  \param elements - elements whose boundary is to be checked
10804  *  \param dimension - defines type of boundary elements to create
10805  *  \param group - a group to store created boundary elements in
10806  *  \param targetMesh - a mesh to store created boundary elements in
10807  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10808  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
10809  *                                boundary elements will be copied into the targetMesh
10810  */
10811 //================================================================================
10812
10813 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10814                                         Bnd_Dimension           dimension,
10815                                         SMESH_Group*            group/*=0*/,
10816                                         SMESH_Mesh*             targetMesh/*=0*/,
10817                                         bool                    toCopyElements/*=false*/,
10818                                         bool                    toCopyExistingBondary/*=false*/)
10819 {
10820   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10821   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10822   // hope that all elements are of the same type, do not check them all
10823   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10824     throw SALOME_Exception(LOCALIZED("wrong element type"));
10825
10826   if ( !targetMesh )
10827     toCopyElements = toCopyExistingBondary = false;
10828
10829   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10830   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10831
10832   SMDS_VolumeTool vTool;
10833   TIDSortedElemSet emptySet, avoidSet;
10834   int inode;
10835
10836   typedef vector<const SMDS_MeshNode*> TConnectivity;
10837
10838   SMDS_ElemIteratorPtr eIt;
10839   if (elements.empty())
10840     eIt = aMesh->elementsIterator(elemType);
10841   else
10842     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10843
10844   while (eIt->more())
10845   {
10846     const SMDS_MeshElement* elem = eIt->next();
10847     const int iQuad = elem->IsQuadratic();
10848
10849     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10850     vector<const SMDS_MeshElement*> presentBndElems;
10851     vector<TConnectivity>           missingBndElems;
10852     TConnectivity nodes;
10853     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10854     {
10855       vTool.SetExternalNormal();
10856       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10857       {
10858         if (!vTool.IsFreeFace(iface))
10859           continue;
10860         int nbFaceNodes = vTool.NbFaceNodes(iface);
10861         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10862         if ( missType == SMDSAbs_Edge ) // boundary edges
10863         {
10864           nodes.resize( 2+iQuad );
10865           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10866           {
10867             for ( int j = 0; j < nodes.size(); ++j )
10868               nodes[j] =nn[i+j];
10869             if ( const SMDS_MeshElement* edge =
10870                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10871               presentBndElems.push_back( edge );
10872             else
10873               missingBndElems.push_back( nodes );
10874           }
10875         }
10876         else // boundary face
10877         {
10878           nodes.clear();
10879           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10880             nodes.push_back( nn[inode] );
10881           if (iQuad)
10882             for ( inode = 1; inode < nbFaceNodes; inode += 2)
10883               nodes.push_back( nn[inode] );
10884
10885           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10886             presentBndElems.push_back( f );
10887           else
10888             missingBndElems.push_back( nodes );
10889         }
10890       }
10891     }
10892     else                     // elem is a face ------------------------------------------
10893     {
10894       avoidSet.clear(), avoidSet.insert( elem );
10895       int nbNodes = elem->NbCornerNodes();
10896       nodes.resize( 2 /*+ iQuad*/);
10897       for ( int i = 0; i < nbNodes; i++ )
10898       {
10899         nodes[0] = elem->GetNode(i);
10900         nodes[1] = elem->GetNode((i+1)%nbNodes);
10901         if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10902           continue; // not free link
10903
10904         //if ( iQuad )
10905         //nodes[2] = elem->GetNode( i + nbNodes );
10906         if ( const SMDS_MeshElement* edge =
10907              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10908           presentBndElems.push_back( edge );
10909         else
10910           missingBndElems.push_back( nodes );
10911       }
10912     }
10913
10914     // 2. Add missing boundary elements
10915     if ( targetMesh != myMesh )
10916       // instead of making a map of nodes in this mesh and targetMesh,
10917       // we create nodes with same IDs. We can renumber them later, if needed
10918       for ( int i = 0; i < missingBndElems.size(); ++i )
10919       {
10920         TConnectivity& srcNodes = missingBndElems[i];
10921         TConnectivity  nodes( srcNodes.size() );
10922         for ( inode = 0; inode < nodes.size(); ++inode )
10923           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10924         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10925       }
10926     else
10927       for ( int i = 0; i < missingBndElems.size(); ++i )
10928       {
10929         TConnectivity&  nodes = missingBndElems[i];
10930         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10931       }
10932
10933     // 3. Copy present boundary elements
10934     if ( toCopyExistingBondary )
10935       for ( int i = 0 ; i < presentBndElems.size(); ++i )
10936       {
10937         const SMDS_MeshElement* e = presentBndElems[i];
10938         TConnectivity nodes( e->NbNodes() );
10939         for ( inode = 0; inode < nodes.size(); ++inode )
10940           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10941         tgtEditor.AddElement(nodes, missType, e->IsPoly());
10942         // leave only missing elements in tgtEditor.myLastCreatedElems
10943         tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10944       }
10945   } // loop on given elements
10946
10947   // 4. Fill group with missing boundary elements
10948   if ( group )
10949   {
10950     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
10951       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
10952         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
10953   }
10954   tgtEditor.myLastCreatedElems.Clear();
10955
10956   // 5. Copy given elements
10957   if ( toCopyElements )
10958   {
10959     if (elements.empty())
10960       eIt = aMesh->elementsIterator(elemType);
10961     else
10962       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10963     while (eIt->more())
10964     {
10965       const SMDS_MeshElement* elem = eIt->next();
10966       TConnectivity nodes( elem->NbNodes() );
10967       for ( inode = 0; inode < nodes.size(); ++inode )
10968         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
10969       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
10970
10971       tgtEditor.myLastCreatedElems.Clear();
10972     }
10973   }
10974   return;
10975 }