Salome HOME
PR: missing groups in CreateFlatElementsOnFacesGroups and names too long for groups...
[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 #include <algorithm>
98 #include <sstream>
99
100 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
101
102 using namespace std;
103 using namespace SMESH::Controls;
104
105 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
106 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
107
108 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
109
110 //=======================================================================
111 //function : SMESH_MeshEditor
112 //purpose  :
113 //=======================================================================
114
115 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
116   :myMesh( theMesh ) // theMesh may be NULL
117 {
118 }
119
120 //=======================================================================
121 /*!
122  * \brief Add element
123  */
124 //=======================================================================
125
126 SMDS_MeshElement*
127 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
128                              const SMDSAbs_ElementType            type,
129                              const bool                           isPoly,
130                              const int                            ID)
131 {
132   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
133   SMDS_MeshElement* e = 0;
134   int nbnode = node.size();
135   SMESHDS_Mesh* mesh = GetMeshDS();
136   switch ( type ) {
137   case SMDSAbs_Face:
138     if ( !isPoly ) {
139       if      (nbnode == 3) {
140         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
141         else           e = mesh->AddFace      (node[0], node[1], node[2] );
142       }
143       else if (nbnode == 4) {
144         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
145         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
146       }
147       else if (nbnode == 6) {
148         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
149                                                node[4], node[5], ID);
150         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
151                                                node[4], node[5] );
152       }
153       else if (nbnode == 8) {
154         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
155                                                node[4], node[5], node[6], node[7], ID);
156         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
157                                                node[4], node[5], node[6], node[7] );
158       }
159     } else {
160       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
161       else           e = mesh->AddPolygonalFace      (node    );
162     }
163     break;
164
165   case SMDSAbs_Volume:
166     if ( !isPoly ) {
167       if      (nbnode == 4) {
168         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
169         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
170       }
171       else if (nbnode == 5) {
172         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
173                                                  node[4], ID);
174         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
175                                                  node[4] );
176       }
177       else if (nbnode == 6) {
178         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
179                                                  node[4], node[5], ID);
180         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
181                                                  node[4], node[5] );
182       }
183       else if (nbnode == 8) {
184         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185                                                  node[4], node[5], node[6], node[7], ID);
186         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
187                                                  node[4], node[5], node[6], node[7] );
188       }
189       else if (nbnode == 10) {
190         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
191                                                  node[4], node[5], node[6], node[7],
192                                                  node[8], node[9], ID);
193         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
194                                                  node[4], node[5], node[6], node[7],
195                                                  node[8], node[9] );
196       }
197       else if (nbnode == 13) {
198         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
199                                                  node[4], node[5], node[6], node[7],
200                                                  node[8], node[9], node[10],node[11],
201                                                  node[12],ID);
202         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
203                                                  node[4], node[5], node[6], node[7],
204                                                  node[8], node[9], node[10],node[11],
205                                                  node[12] );
206       }
207       else if (nbnode == 15) {
208         if ( ID >= 1 ) 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       }
217       else if (nbnode == 20) {
218         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
219                                                  node[4], node[5], node[6], node[7],
220                                                  node[8], node[9], node[10],node[11],
221                                                  node[12],node[13],node[14],node[15],
222                                                  node[16],node[17],node[18],node[19],ID);
223         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
224                                                  node[4], node[5], node[6], node[7],
225                                                  node[8], node[9], node[10],node[11],
226                                                  node[12],node[13],node[14],node[15],
227                                                  node[16],node[17],node[18],node[19] );
228       }
229     }
230     break;
231
232   case SMDSAbs_Edge:
233     if ( nbnode == 2 ) {
234       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
235       else           e = mesh->AddEdge      (node[0], node[1] );
236     }
237     else if ( nbnode == 3 ) {
238       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
239       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
240     }
241     break;
242
243   case SMDSAbs_0DElement:
244     if ( nbnode == 1 ) {
245       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
246       else           e = mesh->Add0DElement      (node[0] );
247     }
248     break;
249
250   case SMDSAbs_Node:
251     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
252     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
253     break;
254
255   default:;
256   }
257   if ( e ) myLastCreatedElems.Append( e );
258   return e;
259 }
260
261 //=======================================================================
262 /*!
263  * \brief Add element
264  */
265 //=======================================================================
266
267 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
268                                                const SMDSAbs_ElementType type,
269                                                const bool                isPoly,
270                                                const int                 ID)
271 {
272   vector<const SMDS_MeshNode*> nodes;
273   nodes.reserve( nodeIDs.size() );
274   vector<int>::const_iterator id = nodeIDs.begin();
275   while ( id != nodeIDs.end() ) {
276     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
277       nodes.push_back( node );
278     else
279       return 0;
280   }
281   return AddElement( nodes, type, isPoly, ID );
282 }
283
284 //=======================================================================
285 //function : Remove
286 //purpose  : Remove a node or an element.
287 //           Modify a compute state of sub-meshes which become empty
288 //=======================================================================
289
290 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
291                               const bool         isNodes )
292 {
293   myLastCreatedElems.Clear();
294   myLastCreatedNodes.Clear();
295
296   SMESHDS_Mesh* aMesh = GetMeshDS();
297   set< SMESH_subMesh *> smmap;
298
299   int removed = 0;
300   list<int>::const_iterator it = theIDs.begin();
301   for ( ; it != theIDs.end(); it++ ) {
302     const SMDS_MeshElement * elem;
303     if ( isNodes )
304       elem = aMesh->FindNode( *it );
305     else
306       elem = aMesh->FindElement( *it );
307     if ( !elem )
308       continue;
309
310     // Notify VERTEX sub-meshes about modification
311     if ( isNodes ) {
312       const SMDS_MeshNode* node = cast2Node( elem );
313       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
314         if ( int aShapeID = node->getshapeId() )
315           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
316             smmap.insert( sm );
317     }
318     // Find sub-meshes to notify about modification
319     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
320     //     while ( nodeIt->more() ) {
321     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
322     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
323     //       if ( aPosition.get() ) {
324     //         if ( int aShapeID = aPosition->GetShapeId() ) {
325     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
326     //             smmap.insert( sm );
327     //         }
328     //       }
329     //     }
330
331     // Do remove
332     if ( isNodes )
333       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
334     else
335       aMesh->RemoveElement( elem );
336     removed++;
337   }
338
339   // Notify sub-meshes about modification
340   if ( !smmap.empty() ) {
341     set< SMESH_subMesh *>::iterator smIt;
342     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
343       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
344   }
345
346   //   // Check if the whole mesh becomes empty
347   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
348   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
349
350   return removed;
351 }
352
353 //=======================================================================
354 //function : FindShape
355 //purpose  : Return an index of the shape theElem is on
356 //           or zero if a shape not found
357 //=======================================================================
358
359 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
360 {
361   myLastCreatedElems.Clear();
362   myLastCreatedNodes.Clear();
363
364   SMESHDS_Mesh * aMesh = GetMeshDS();
365   if ( aMesh->ShapeToMesh().IsNull() )
366     return 0;
367
368   int aShapeID = theElem->getshapeId();
369   if ( aShapeID < 1 )
370     return 0;
371
372   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
373     if ( sm->Contains( theElem ))
374       return aShapeID;
375
376   if ( theElem->GetType() == SMDSAbs_Node ) {
377     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
378   }
379   else {
380     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
381   }
382
383   TopoDS_Shape aShape; // the shape a node of theElem is on
384   if ( theElem->GetType() != SMDSAbs_Node )
385   {
386     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
387     while ( nodeIt->more() ) {
388       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
389       if ((aShapeID = node->getshapeId()) > 0) {
390         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
391           if ( sm->Contains( theElem ))
392             return aShapeID;
393           if ( aShape.IsNull() )
394             aShape = aMesh->IndexToShape( aShapeID );
395         }
396       }
397     }
398   }
399
400   // None of nodes is on a proper shape,
401   // find the shape among ancestors of aShape on which a node is
402   if ( !aShape.IsNull() ) {
403     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
404     for ( ; ancIt.More(); ancIt.Next() ) {
405       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
406       if ( sm && sm->Contains( theElem ))
407         return aMesh->ShapeToIndex( ancIt.Value() );
408     }
409   }
410   else
411   {
412     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
413     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
414     for ( ; id_sm != id2sm.end(); ++id_sm )
415       if ( id_sm->second->Contains( theElem ))
416         return id_sm->first;
417   }
418
419   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
420   return 0;
421 }
422
423 //=======================================================================
424 //function : IsMedium
425 //purpose  :
426 //=======================================================================
427
428 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
429                                 const SMDSAbs_ElementType typeToCheck)
430 {
431   bool isMedium = false;
432   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
433   while (it->more() && !isMedium ) {
434     const SMDS_MeshElement* elem = it->next();
435     isMedium = elem->IsMediumNode(node);
436   }
437   return isMedium;
438 }
439
440 //=======================================================================
441 //function : ShiftNodesQuadTria
442 //purpose  : auxilary
443 //           Shift nodes in the array corresponded to quadratic triangle
444 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
445 //=======================================================================
446 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
447 {
448   const SMDS_MeshNode* nd1 = aNodes[0];
449   aNodes[0] = aNodes[1];
450   aNodes[1] = aNodes[2];
451   aNodes[2] = nd1;
452   const SMDS_MeshNode* nd2 = aNodes[3];
453   aNodes[3] = aNodes[4];
454   aNodes[4] = aNodes[5];
455   aNodes[5] = nd2;
456 }
457
458 //=======================================================================
459 //function : GetNodesFromTwoTria
460 //purpose  : auxilary
461 //           Shift nodes in the array corresponded to quadratic triangle
462 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
463 //=======================================================================
464 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
465                                 const SMDS_MeshElement * theTria2,
466                                 const SMDS_MeshNode* N1[],
467                                 const SMDS_MeshNode* N2[])
468 {
469   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
470   int i=0;
471   while(i<6) {
472     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
473     i++;
474   }
475   if(it->more()) return false;
476   it = theTria2->nodesIterator();
477   i=0;
478   while(i<6) {
479     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
480     i++;
481   }
482   if(it->more()) return false;
483
484   int sames[3] = {-1,-1,-1};
485   int nbsames = 0;
486   int j;
487   for(i=0; i<3; i++) {
488     for(j=0; j<3; j++) {
489       if(N1[i]==N2[j]) {
490         sames[i] = j;
491         nbsames++;
492         break;
493       }
494     }
495   }
496   if(nbsames!=2) return false;
497   if(sames[0]>-1) {
498     ShiftNodesQuadTria(N1);
499     if(sames[1]>-1) {
500       ShiftNodesQuadTria(N1);
501     }
502   }
503   i = sames[0] + sames[1] + sames[2];
504   for(; i<2; i++) {
505     ShiftNodesQuadTria(N2);
506   }
507   // now we receive following N1 and N2 (using numeration as above image)
508   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
509   // i.e. first nodes from both arrays determ new diagonal
510   return true;
511 }
512
513 //=======================================================================
514 //function : InverseDiag
515 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
516 //           but having other common link.
517 //           Return False if args are improper
518 //=======================================================================
519
520 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
521                                     const SMDS_MeshElement * theTria2 )
522 {
523   MESSAGE("InverseDiag");
524   myLastCreatedElems.Clear();
525   myLastCreatedNodes.Clear();
526
527   if (!theTria1 || !theTria2)
528     return false;
529
530   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
531   if (!F1) return false;
532   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
533   if (!F2) return false;
534   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
535       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
536
537     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
538     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
539     //    |/ |                                         | \|
540     //  B +--+ 2                                     B +--+ 2
541
542     // put nodes in array and find out indices of the same ones
543     const SMDS_MeshNode* aNodes [6];
544     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
545     int i = 0;
546     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
547     while ( it->more() ) {
548       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
549
550       if ( i > 2 ) // theTria2
551         // find same node of theTria1
552         for ( int j = 0; j < 3; j++ )
553           if ( aNodes[ i ] == aNodes[ j ]) {
554             sameInd[ j ] = i;
555             sameInd[ i ] = j;
556             break;
557           }
558       // next
559       i++;
560       if ( i == 3 ) {
561         if ( it->more() )
562           return false; // theTria1 is not a triangle
563         it = theTria2->nodesIterator();
564       }
565       if ( i == 6 && it->more() )
566         return false; // theTria2 is not a triangle
567     }
568
569     // find indices of 1,2 and of A,B in theTria1
570     int iA = 0, iB = 0, i1 = 0, i2 = 0;
571     for ( i = 0; i < 6; i++ ) {
572       if ( sameInd [ i ] == 0 ) {
573         if ( i < 3 ) i1 = i;
574         else         i2 = i;
575       }
576       else if (i < 3) {
577         if ( iA ) iB = i;
578         else      iA = i;
579       }
580     }
581     // nodes 1 and 2 should not be the same
582     if ( aNodes[ i1 ] == aNodes[ i2 ] )
583       return false;
584
585     // theTria1: A->2
586     aNodes[ iA ] = aNodes[ i2 ];
587     // theTria2: B->1
588     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
589
590     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
591     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
592
593     return true;
594
595   } // end if(F1 && F2)
596
597   // check case of quadratic faces
598   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
599     return false;
600   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
601     return false;
602
603   //       5
604   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
605   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
606   //    |   / |
607   //  7 +  +  + 6
608   //    | /9  |
609   //    |/    |
610   //  4 +--+--+ 3
611   //       8
612
613   const SMDS_MeshNode* N1 [6];
614   const SMDS_MeshNode* N2 [6];
615   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
616     return false;
617   // now we receive following N1 and N2 (using numeration as above image)
618   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
619   // i.e. first nodes from both arrays determ new diagonal
620
621   const SMDS_MeshNode* N1new [6];
622   const SMDS_MeshNode* N2new [6];
623   N1new[0] = N1[0];
624   N1new[1] = N2[0];
625   N1new[2] = N2[1];
626   N1new[3] = N1[4];
627   N1new[4] = N2[3];
628   N1new[5] = N1[5];
629   N2new[0] = N1[0];
630   N2new[1] = N1[1];
631   N2new[2] = N2[0];
632   N2new[3] = N1[3];
633   N2new[4] = N2[5];
634   N2new[5] = N1[4];
635   // replaces nodes in faces
636   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
637   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
638
639   return true;
640 }
641
642 //=======================================================================
643 //function : findTriangles
644 //purpose  : find triangles sharing theNode1-theNode2 link
645 //=======================================================================
646
647 static bool findTriangles(const SMDS_MeshNode *    theNode1,
648                           const SMDS_MeshNode *    theNode2,
649                           const SMDS_MeshElement*& theTria1,
650                           const SMDS_MeshElement*& theTria2)
651 {
652   if ( !theNode1 || !theNode2 ) return false;
653
654   theTria1 = theTria2 = 0;
655
656   set< const SMDS_MeshElement* > emap;
657   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
658   while (it->more()) {
659     const SMDS_MeshElement* elem = it->next();
660     if ( elem->NbNodes() == 3 )
661       emap.insert( elem );
662   }
663   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
664   while (it->more()) {
665     const SMDS_MeshElement* elem = it->next();
666     if ( emap.find( elem ) != emap.end() ) {
667       if ( theTria1 ) {
668         // theTria1 must be element with minimum ID
669         if( theTria1->GetID() < elem->GetID() ) {
670           theTria2 = elem;
671         }
672         else {
673           theTria2 = theTria1;
674           theTria1 = elem;
675         }
676         break;
677       }
678       else {
679         theTria1 = elem;
680       }
681     }
682   }
683   return ( theTria1 && theTria2 );
684 }
685
686 //=======================================================================
687 //function : InverseDiag
688 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
689 //           with ones built on the same 4 nodes but having other common link.
690 //           Return false if proper faces not found
691 //=======================================================================
692
693 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
694                                     const SMDS_MeshNode * theNode2)
695 {
696   myLastCreatedElems.Clear();
697   myLastCreatedNodes.Clear();
698
699   MESSAGE( "::InverseDiag()" );
700
701   const SMDS_MeshElement *tr1, *tr2;
702   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
703     return false;
704
705   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
706   if (!F1) return false;
707   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
708   if (!F2) return false;
709   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
710       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
711
712     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
713     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
714     //    |/ |                                    | \|
715     //  B +--+ 2                                B +--+ 2
716
717     // put nodes in array
718     // and find indices of 1,2 and of A in tr1 and of B in tr2
719     int i, iA1 = 0, i1 = 0;
720     const SMDS_MeshNode* aNodes1 [3];
721     SMDS_ElemIteratorPtr it;
722     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
723       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
724       if ( aNodes1[ i ] == theNode1 )
725         iA1 = i; // node A in tr1
726       else if ( aNodes1[ i ] != theNode2 )
727         i1 = i;  // node 1
728     }
729     int iB2 = 0, i2 = 0;
730     const SMDS_MeshNode* aNodes2 [3];
731     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
732       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
733       if ( aNodes2[ i ] == theNode2 )
734         iB2 = i; // node B in tr2
735       else if ( aNodes2[ i ] != theNode1 )
736         i2 = i;  // node 2
737     }
738
739     // nodes 1 and 2 should not be the same
740     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
741       return false;
742
743     // tr1: A->2
744     aNodes1[ iA1 ] = aNodes2[ i2 ];
745     // tr2: B->1
746     aNodes2[ iB2 ] = aNodes1[ i1 ];
747
748     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
749     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
750
751     return true;
752   }
753
754   // check case of quadratic faces
755   return InverseDiag(tr1,tr2);
756 }
757
758 //=======================================================================
759 //function : getQuadrangleNodes
760 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
761 //           fusion of triangles tr1 and tr2 having shared link on
762 //           theNode1 and theNode2
763 //=======================================================================
764
765 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
766                         const SMDS_MeshNode *    theNode1,
767                         const SMDS_MeshNode *    theNode2,
768                         const SMDS_MeshElement * tr1,
769                         const SMDS_MeshElement * tr2 )
770 {
771   if( tr1->NbNodes() != tr2->NbNodes() )
772     return false;
773   // find the 4-th node to insert into tr1
774   const SMDS_MeshNode* n4 = 0;
775   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
776   int i=0;
777   while ( !n4 && i<3 ) {
778     const SMDS_MeshNode * n = cast2Node( it->next() );
779     i++;
780     bool isDiag = ( n == theNode1 || n == theNode2 );
781     if ( !isDiag )
782       n4 = n;
783   }
784   // Make an array of nodes to be in a quadrangle
785   int iNode = 0, iFirstDiag = -1;
786   it = tr1->nodesIterator();
787   i=0;
788   while ( i<3 ) {
789     const SMDS_MeshNode * n = cast2Node( it->next() );
790     i++;
791     bool isDiag = ( n == theNode1 || n == theNode2 );
792     if ( isDiag ) {
793       if ( iFirstDiag < 0 )
794         iFirstDiag = iNode;
795       else if ( iNode - iFirstDiag == 1 )
796         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
797     }
798     else if ( n == n4 ) {
799       return false; // tr1 and tr2 should not have all the same nodes
800     }
801     theQuadNodes[ iNode++ ] = n;
802   }
803   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
804     theQuadNodes[ iNode ] = n4;
805
806   return true;
807 }
808
809 //=======================================================================
810 //function : DeleteDiag
811 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
812 //           with a quadrangle built on the same 4 nodes.
813 //           Return false if proper faces not found
814 //=======================================================================
815
816 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
817                                    const SMDS_MeshNode * theNode2)
818 {
819   myLastCreatedElems.Clear();
820   myLastCreatedNodes.Clear();
821
822   MESSAGE( "::DeleteDiag()" );
823
824   const SMDS_MeshElement *tr1, *tr2;
825   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
826     return false;
827
828   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
829   if (!F1) return false;
830   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
831   if (!F2) return false;
832   SMESHDS_Mesh * aMesh = GetMeshDS();
833
834   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
835       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
836
837     const SMDS_MeshNode* aNodes [ 4 ];
838     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
839       return false;
840
841     const SMDS_MeshElement* newElem = 0;
842     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
843     myLastCreatedElems.Append(newElem);
844     AddToSameGroups( newElem, tr1, aMesh );
845     int aShapeId = tr1->getshapeId();
846     if ( aShapeId )
847       {
848         aMesh->SetMeshElementOnShape( newElem, aShapeId );
849       }
850     aMesh->RemoveElement( tr1 );
851     aMesh->RemoveElement( tr2 );
852
853     return true;
854   }
855
856   // check case of quadratic faces
857   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
858     return false;
859   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
860     return false;
861
862   //       5
863   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
864   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
865   //    |   / |
866   //  7 +  +  + 6
867   //    | /9  |
868   //    |/    |
869   //  4 +--+--+ 3
870   //       8
871
872   const SMDS_MeshNode* N1 [6];
873   const SMDS_MeshNode* N2 [6];
874   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
875     return false;
876   // now we receive following N1 and N2 (using numeration as above image)
877   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
878   // i.e. first nodes from both arrays determ new diagonal
879
880   const SMDS_MeshNode* aNodes[8];
881   aNodes[0] = N1[0];
882   aNodes[1] = N1[1];
883   aNodes[2] = N2[0];
884   aNodes[3] = N2[1];
885   aNodes[4] = N1[3];
886   aNodes[5] = N2[5];
887   aNodes[6] = N2[3];
888   aNodes[7] = N1[5];
889
890   const SMDS_MeshElement* newElem = 0;
891   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
892                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
893   myLastCreatedElems.Append(newElem);
894   AddToSameGroups( newElem, tr1, aMesh );
895   int aShapeId = tr1->getshapeId();
896   if ( aShapeId )
897     {
898       aMesh->SetMeshElementOnShape( newElem, aShapeId );
899     }
900   aMesh->RemoveElement( tr1 );
901   aMesh->RemoveElement( tr2 );
902
903   // remove middle node (9)
904   GetMeshDS()->RemoveNode( N1[4] );
905
906   return true;
907 }
908
909 //=======================================================================
910 //function : Reorient
911 //purpose  : Reverse theElement orientation
912 //=======================================================================
913
914 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
915 {
916   MESSAGE("Reorient");
917   myLastCreatedElems.Clear();
918   myLastCreatedNodes.Clear();
919
920   if (!theElem)
921     return false;
922   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
923   if ( !it || !it->more() )
924     return false;
925
926   switch ( theElem->GetType() ) {
927
928   case SMDSAbs_Edge:
929   case SMDSAbs_Face: {
930     if(!theElem->IsQuadratic()) {
931       int i = theElem->NbNodes();
932       vector<const SMDS_MeshNode*> aNodes( i );
933       while ( it->more() )
934         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
935       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
936     }
937     else {
938       // quadratic elements
939       if(theElem->GetType()==SMDSAbs_Edge) {
940         vector<const SMDS_MeshNode*> aNodes(3);
941         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
942         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
943         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
944         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
945       }
946       else {
947         int nbn = theElem->NbNodes();
948         vector<const SMDS_MeshNode*> aNodes(nbn);
949         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
950         int i=1;
951         for(; i<nbn/2; i++) {
952           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
953         }
954         for(i=0; i<nbn/2; i++) {
955           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
956         }
957         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
958       }
959     }
960   }
961   case SMDSAbs_Volume: {
962     if (theElem->IsPoly()) {
963       // TODO reorient vtk polyhedron
964       MESSAGE("reorient vtk polyhedron ?");
965       const SMDS_VtkVolume* aPolyedre =
966         dynamic_cast<const SMDS_VtkVolume*>( theElem );
967       if (!aPolyedre) {
968         MESSAGE("Warning: bad volumic element");
969         return false;
970       }
971
972       int nbFaces = aPolyedre->NbFaces();
973       vector<const SMDS_MeshNode *> poly_nodes;
974       vector<int> quantities (nbFaces);
975
976       // reverse each face of the polyedre
977       for (int iface = 1; iface <= nbFaces; iface++) {
978         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
979         quantities[iface - 1] = nbFaceNodes;
980
981         for (inode = nbFaceNodes; inode >= 1; inode--) {
982           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
983           poly_nodes.push_back(curNode);
984         }
985       }
986
987       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
988
989     }
990     else {
991       SMDS_VolumeTool vTool;
992       if ( !vTool.Set( theElem ))
993         return false;
994       vTool.Inverse();
995       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
996       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
997     }
998   }
999   default:;
1000   }
1001
1002   return false;
1003 }
1004
1005 //=======================================================================
1006 //function : getBadRate
1007 //purpose  :
1008 //=======================================================================
1009
1010 static double getBadRate (const SMDS_MeshElement*               theElem,
1011                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1012 {
1013   SMESH::Controls::TSequenceOfXYZ P;
1014   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1015     return 1e100;
1016   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1017   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1018 }
1019
1020 //=======================================================================
1021 //function : QuadToTri
1022 //purpose  : Cut quadrangles into triangles.
1023 //           theCrit is used to select a diagonal to cut
1024 //=======================================================================
1025
1026 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1027                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1028 {
1029   myLastCreatedElems.Clear();
1030   myLastCreatedNodes.Clear();
1031
1032   MESSAGE( "::QuadToTri()" );
1033
1034   if ( !theCrit.get() )
1035     return false;
1036
1037   SMESHDS_Mesh * aMesh = GetMeshDS();
1038
1039   Handle(Geom_Surface) surface;
1040   SMESH_MesherHelper   helper( *GetMesh() );
1041
1042   TIDSortedElemSet::iterator itElem;
1043   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1044     const SMDS_MeshElement* elem = *itElem;
1045     if ( !elem || elem->GetType() != SMDSAbs_Face )
1046       continue;
1047     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1048       continue;
1049
1050     // retrieve element nodes
1051     const SMDS_MeshNode* aNodes [8];
1052     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1053     int i = 0;
1054     while ( itN->more() )
1055       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1056
1057     // compare two sets of possible triangles
1058     double aBadRate1, aBadRate2; // to what extent a set is bad
1059     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1060     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1061     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1062
1063     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1064     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1065     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1066
1067     int aShapeId = FindShape( elem );
1068     const SMDS_MeshElement* newElem1 = 0;
1069     const SMDS_MeshElement* newElem2 = 0;
1070
1071     if( !elem->IsQuadratic() ) {
1072
1073       // split liner quadrangle
1074       if ( aBadRate1 <= aBadRate2 ) {
1075         // tr1 + tr2 is better
1076         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1077         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1078       }
1079       else {
1080         // tr3 + tr4 is better
1081         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1082         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1083       }
1084     }
1085     else {
1086
1087       // split quadratic quadrangle
1088
1089       // get surface elem is on
1090       if ( aShapeId != helper.GetSubShapeID() ) {
1091         surface.Nullify();
1092         TopoDS_Shape shape;
1093         if ( aShapeId > 0 )
1094           shape = aMesh->IndexToShape( aShapeId );
1095         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1096           TopoDS_Face face = TopoDS::Face( shape );
1097           surface = BRep_Tool::Surface( face );
1098           if ( !surface.IsNull() )
1099             helper.SetSubShape( shape );
1100         }
1101       }
1102       // get elem nodes
1103       const SMDS_MeshNode* aNodes [8];
1104       const SMDS_MeshNode* inFaceNode = 0;
1105       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1106       int i = 0;
1107       while ( itN->more() ) {
1108         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1109         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1110              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1111         {
1112           inFaceNode = aNodes[ i-1 ];
1113         }
1114       }
1115       // find middle point for (0,1,2,3)
1116       // and create a node in this point;
1117       gp_XYZ p( 0,0,0 );
1118       if ( surface.IsNull() ) {
1119         for(i=0; i<4; i++)
1120           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1121         p /= 4;
1122       }
1123       else {
1124         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1125         gp_XY uv( 0,0 );
1126         for(i=0; i<4; i++)
1127           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1128         uv /= 4.;
1129         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1130       }
1131       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1132       myLastCreatedNodes.Append(newN);
1133
1134       // create a new element
1135       const SMDS_MeshNode* N[6];
1136       if ( aBadRate1 <= aBadRate2 ) {
1137         N[0] = aNodes[0];
1138         N[1] = aNodes[1];
1139         N[2] = aNodes[2];
1140         N[3] = aNodes[4];
1141         N[4] = aNodes[5];
1142         N[5] = newN;
1143         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1144                                   aNodes[6], aNodes[7], newN );
1145         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1146                                   newN,      aNodes[4], aNodes[5] );
1147       }
1148       else {
1149         N[0] = aNodes[1];
1150         N[1] = aNodes[2];
1151         N[2] = aNodes[3];
1152         N[3] = aNodes[5];
1153         N[4] = aNodes[6];
1154         N[5] = newN;
1155         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1156                                   aNodes[7], aNodes[4], newN );
1157         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1158                                   newN,      aNodes[5], aNodes[6] );
1159       }
1160     } // quadratic case
1161
1162     // care of a new element
1163
1164     myLastCreatedElems.Append(newElem1);
1165     myLastCreatedElems.Append(newElem2);
1166     AddToSameGroups( newElem1, elem, aMesh );
1167     AddToSameGroups( newElem2, elem, aMesh );
1168
1169     // put a new triangle on the same shape
1170     if ( aShapeId )
1171       {
1172         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1173         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1174       }
1175     aMesh->RemoveElement( elem );
1176   }
1177   return true;
1178 }
1179
1180 //=======================================================================
1181 //function : BestSplit
1182 //purpose  : Find better diagonal for cutting.
1183 //=======================================================================
1184
1185 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1186                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1187 {
1188   myLastCreatedElems.Clear();
1189   myLastCreatedNodes.Clear();
1190
1191   if (!theCrit.get())
1192     return -1;
1193
1194   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1195     return -1;
1196
1197   if( theQuad->NbNodes()==4 ||
1198       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1199
1200     // retrieve element nodes
1201     const SMDS_MeshNode* aNodes [4];
1202     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1203     int i = 0;
1204     //while (itN->more())
1205     while (i<4) {
1206       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1207     }
1208     // compare two sets of possible triangles
1209     double aBadRate1, aBadRate2; // to what extent a set is bad
1210     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1211     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1212     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1213
1214     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1215     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1216     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1217
1218     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1219       return 1; // diagonal 1-3
1220
1221     return 2; // diagonal 2-4
1222   }
1223   return -1;
1224 }
1225
1226 namespace
1227 {
1228   // Methods of splitting volumes into tetra
1229
1230   const int theHexTo5_1[5*4+1] =
1231     {
1232       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1233     };
1234   const int theHexTo5_2[5*4+1] =
1235     {
1236       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1237     };
1238   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1239
1240   const int theHexTo6_1[6*4+1] =
1241     {
1242       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
1243     };
1244   const int theHexTo6_2[6*4+1] =
1245     {
1246       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
1247     };
1248   const int theHexTo6_3[6*4+1] =
1249     {
1250       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
1251     };
1252   const int theHexTo6_4[6*4+1] =
1253     {
1254       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
1255     };
1256   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1257
1258   const int thePyraTo2_1[2*4+1] =
1259     {
1260       0, 1, 2, 4,    0, 2, 3, 4,   -1
1261     };
1262   const int thePyraTo2_2[2*4+1] =
1263     {
1264       1, 2, 3, 4,    1, 3, 0, 4,   -1
1265     };
1266   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1267
1268   const int thePentaTo3_1[3*4+1] =
1269     {
1270       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1271     };
1272   const int thePentaTo3_2[3*4+1] =
1273     {
1274       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1275     };
1276   const int thePentaTo3_3[3*4+1] =
1277     {
1278       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1279     };
1280   const int thePentaTo3_4[3*4+1] =
1281     {
1282       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1283     };
1284   const int thePentaTo3_5[3*4+1] =
1285     {
1286       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1287     };
1288   const int thePentaTo3_6[3*4+1] =
1289     {
1290       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1291     };
1292   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1293                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1294
1295   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1296   {
1297     int _n1, _n2, _n3;
1298     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1299     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1300     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1301   };
1302   struct TSplitMethod
1303   {
1304     int        _nbTetra;
1305     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1306     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1307     bool       _ownConn;      //!< to delete _connectivity in destructor
1308     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1309
1310     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1311       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1312     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1313     bool hasFacet( const TTriangleFacet& facet ) const
1314     {
1315       const int* tetConn = _connectivity;
1316       for ( ; tetConn[0] >= 0; tetConn += 4 )
1317         if (( facet.contains( tetConn[0] ) +
1318               facet.contains( tetConn[1] ) +
1319               facet.contains( tetConn[2] ) +
1320               facet.contains( tetConn[3] )) == 3 )
1321           return true;
1322       return false;
1323     }
1324   };
1325
1326   //=======================================================================
1327   /*!
1328    * \brief return TSplitMethod for the given element
1329    */
1330   //=======================================================================
1331
1332   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1333   {
1334     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1335
1336     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1337     // an edge and a face barycenter; tertaherdons are based on triangles and
1338     // a volume barycenter
1339     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1340
1341     // Find out how adjacent volumes are split
1342
1343     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1344     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1345     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1346     {
1347       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1348       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1349       if ( nbNodes < 4 ) continue;
1350
1351       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1352       const int* nInd = vol.GetFaceNodesIndices( iF );
1353       if ( nbNodes == 4 )
1354       {
1355         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1356         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1357         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1358         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1359       }
1360       else
1361       {
1362         int iCom = 0; // common node of triangle faces to split into
1363         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1364         {
1365           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1366                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1367                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1368           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1369                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1370                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1371           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1372           {
1373             triaSplits.push_back( t012 );
1374             triaSplits.push_back( t023 );
1375             break;
1376           }
1377         }
1378       }
1379       if ( !triaSplits.empty() )
1380         hasAdjacentSplits = true;
1381     }
1382
1383     // Among variants of split method select one compliant with adjacent volumes
1384
1385     TSplitMethod method;
1386     if ( !vol.Element()->IsPoly() && !is24TetMode )
1387     {
1388       int nbVariants = 2, nbTet = 0;
1389       const int** connVariants = 0;
1390       switch ( vol.Element()->GetEntityType() )
1391       {
1392       case SMDSEntity_Hexa:
1393       case SMDSEntity_Quad_Hexa:
1394         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1395           connVariants = theHexTo5, nbTet = 5;
1396         else
1397           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1398         break;
1399       case SMDSEntity_Pyramid:
1400       case SMDSEntity_Quad_Pyramid:
1401         connVariants = thePyraTo2;  nbTet = 2;
1402         break;
1403       case SMDSEntity_Penta:
1404       case SMDSEntity_Quad_Penta:
1405         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1406         break;
1407       default:
1408         nbVariants = 0;
1409       }
1410       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1411       {
1412         // check method compliancy with adjacent tetras,
1413         // all found splits must be among facets of tetras described by this method
1414         method = TSplitMethod( nbTet, connVariants[variant] );
1415         if ( hasAdjacentSplits && method._nbTetra > 0 )
1416         {
1417           bool facetCreated = true;
1418           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1419           {
1420             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1421             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1422               facetCreated = method.hasFacet( *facet );
1423           }
1424           if ( !facetCreated )
1425             method = TSplitMethod(0); // incompatible method
1426         }
1427       }
1428     }
1429     if ( method._nbTetra < 1 )
1430     {
1431       // No standard method is applicable, use a generic solution:
1432       // each facet of a volume is split into triangles and
1433       // each of triangles and a volume barycenter form a tetrahedron.
1434
1435       int* connectivity = new int[ maxTetConnSize + 1 ];
1436       method._connectivity = connectivity;
1437       method._ownConn = true;
1438       method._baryNode = true;
1439
1440       int connSize = 0;
1441       int baryCenInd = vol.NbNodes();
1442       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1443       {
1444         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1445         const int*   nInd = vol.GetFaceNodesIndices( iF );
1446         // find common node of triangle facets of tetra to create
1447         int iCommon = 0; // index in linear numeration
1448         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1449         if ( !triaSplits.empty() )
1450         {
1451           // by found facets
1452           const TTriangleFacet* facet = &triaSplits.front();
1453           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1454             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1455                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1456               break;
1457         }
1458         else if ( nbNodes > 3 && !is24TetMode )
1459         {
1460           // find the best method of splitting into triangles by aspect ratio
1461           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1462           map< double, int > badness2iCommon;
1463           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1464           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1465           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1466             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1467             {
1468               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1469                                       nodes[ iQ*((iLast-1)%nbNodes)],
1470                                       nodes[ iQ*((iLast  )%nbNodes)]);
1471               double badness = getBadRate( &tria, aspectRatio );
1472               badness2iCommon.insert( make_pair( badness, iCommon ));
1473             }
1474           // use iCommon with lowest badness
1475           iCommon = badness2iCommon.begin()->second;
1476         }
1477         if ( iCommon >= nbNodes )
1478           iCommon = 0; // something wrong
1479
1480         // fill connectivity of tetrahedra based on a current face
1481         int nbTet = nbNodes - 2;
1482         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1483         {
1484           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1485           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1486           nbTet = nbNodes;
1487           for ( int i = 0; i < nbTet; ++i )
1488           {
1489             int i1 = i, i2 = (i+1) % nbNodes;
1490             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1491             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1492             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1493             connectivity[ connSize++ ] = faceBaryCenInd;
1494             connectivity[ connSize++ ] = baryCenInd;
1495           }
1496         }
1497         else
1498         {
1499           for ( int i = 0; i < nbTet; ++i )
1500           {
1501             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1502             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1503             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1504             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1505             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1506             connectivity[ connSize++ ] = baryCenInd;
1507           }
1508         }
1509         method._nbTetra += nbTet;
1510       }
1511       connectivity[ connSize++ ] = -1;
1512     }
1513     return method;
1514   }
1515   //================================================================================
1516   /*!
1517    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1518    */
1519   //================================================================================
1520
1521   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1522   {
1523     // find the tetrahedron including the three nodes of facet
1524     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1525     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1526     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1527     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1528     while ( volIt1->more() )
1529     {
1530       const SMDS_MeshElement* v = volIt1->next();
1531       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1532         continue;
1533       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1534       while ( volIt2->more() )
1535         if ( v != volIt2->next() )
1536           continue;
1537       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1538       while ( volIt3->more() )
1539         if ( v == volIt3->next() )
1540           return true;
1541     }
1542     return false;
1543   }
1544
1545   //=======================================================================
1546   /*!
1547    * \brief A key of a face of volume
1548    */
1549   //=======================================================================
1550
1551   struct TVolumeFaceKey: pair< int, pair< int, int> >
1552   {
1553     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1554     {
1555       TIDSortedNodeSet sortedNodes;
1556       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1557       int nbNodes = vol.NbFaceNodes( iF );
1558       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1559       for ( int i = 0; i < nbNodes; i += iQ )
1560         sortedNodes.insert( fNodes[i] );
1561       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1562       first = (*(n++))->GetID();
1563       second.first = (*(n++))->GetID();
1564       second.second = (*(n++))->GetID();
1565     }
1566   };
1567 } // namespace
1568
1569 //=======================================================================
1570 //function : SplitVolumesIntoTetra
1571 //purpose  : Split volumic elements into tetrahedra.
1572 //=======================================================================
1573
1574 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1575                                               const int                theMethodFlags)
1576 {
1577   // std-like iterator on coordinates of nodes of mesh element
1578   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1579   NXyzIterator xyzEnd;
1580
1581   SMDS_VolumeTool    volTool;
1582   SMESH_MesherHelper helper( *GetMesh());
1583
1584   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1585   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1586   
1587   SMESH_SequenceOfElemPtr newNodes, newElems;
1588
1589   // map face of volume to it's baricenrtic node
1590   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1591   double bc[3];
1592
1593   TIDSortedElemSet::const_iterator elem = theElems.begin();
1594   for ( ; elem != theElems.end(); ++elem )
1595   {
1596     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1597     if ( geomType <= SMDSEntity_Quad_Tetra )
1598       continue; // tetra or face or ...
1599
1600     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1601
1602     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1603     if ( splitMethod._nbTetra < 1 ) continue;
1604
1605     // find submesh to add new tetras to
1606     if ( !subMesh || !subMesh->Contains( *elem ))
1607     {
1608       int shapeID = FindShape( *elem );
1609       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1610       subMesh = GetMeshDS()->MeshElements( shapeID );
1611     }
1612     int iQ;
1613     if ( (*elem)->IsQuadratic() )
1614     {
1615       iQ = 2;
1616       // add quadratic links to the helper
1617       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1618       {
1619         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1620         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1621           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1622       }
1623       helper.SetIsQuadratic( true );
1624     }
1625     else
1626     {
1627       iQ = 1;
1628       helper.SetIsQuadratic( false );
1629     }
1630     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1631     if ( splitMethod._baryNode )
1632     {
1633       // make a node at barycenter
1634       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1635       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1636       nodes.push_back( gcNode );
1637       newNodes.Append( gcNode );
1638     }
1639     if ( !splitMethod._faceBaryNode.empty() )
1640     {
1641       // make or find baricentric nodes of faces
1642       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1643       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1644       {
1645         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1646           volFace2BaryNode.insert
1647           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1648         if ( !f_n->second )
1649         {
1650           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1651           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1652         }
1653         nodes.push_back( iF_n->second = f_n->second );
1654       }
1655     }
1656
1657     // make tetras
1658     helper.SetElementsOnShape( true );
1659     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1660     const int* tetConn = splitMethod._connectivity;
1661     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1662       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1663                                                        nodes[ tetConn[1] ],
1664                                                        nodes[ tetConn[2] ],
1665                                                        nodes[ tetConn[3] ]));
1666
1667     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1668
1669     // Split faces on sides of the split volume
1670
1671     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1672     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1673     {
1674       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1675       if ( nbNodes < 4 ) continue;
1676
1677       // find an existing face
1678       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1679                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1680       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1681       {
1682         // make triangles
1683         helper.SetElementsOnShape( false );
1684         vector< const SMDS_MeshElement* > triangles;
1685
1686         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1687         if ( iF_n != splitMethod._faceBaryNode.end() )
1688         {
1689           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1690           {
1691             const SMDS_MeshNode* n1 = fNodes[iN];
1692             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1693             const SMDS_MeshNode *n3 = iF_n->second;
1694             if ( !volTool.IsFaceExternal( iF ))
1695               swap( n2, n3 );
1696             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1697           }
1698         }
1699         else
1700         {
1701           // among possible triangles create ones discribed by split method
1702           const int* nInd = volTool.GetFaceNodesIndices( iF );
1703           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1704           int iCom = 0; // common node of triangle faces to split into
1705           list< TTriangleFacet > facets;
1706           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1707           {
1708             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1709                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1710                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1711             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1712                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1713                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1714             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1715             {
1716               facets.push_back( t012 );
1717               facets.push_back( t023 );
1718               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1719                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1720                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1721                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1722               break;
1723             }
1724           }
1725           list< TTriangleFacet >::iterator facet = facets.begin();
1726           for ( ; facet != facets.end(); ++facet )
1727           {
1728             if ( !volTool.IsFaceExternal( iF ))
1729               swap( facet->_n2, facet->_n3 );
1730             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1731                                                  volNodes[ facet->_n2 ],
1732                                                  volNodes[ facet->_n3 ]));
1733           }
1734         }
1735         // find submesh to add new triangles in
1736         if ( !fSubMesh || !fSubMesh->Contains( face ))
1737         {
1738           int shapeID = FindShape( face );
1739           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1740         }
1741         for ( int i = 0; i < triangles.size(); ++i )
1742         {
1743           if ( !triangles[i] ) continue;
1744           if ( fSubMesh )
1745             fSubMesh->AddElement( triangles[i]);
1746           newElems.Append( triangles[i] );
1747         }
1748         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1749         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1750       }
1751
1752     } // loop on volume faces to split them into triangles
1753
1754     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1755
1756   } // loop on volumes to split
1757
1758   myLastCreatedNodes = newNodes;
1759   myLastCreatedElems = newElems;
1760 }
1761
1762 //=======================================================================
1763 //function : AddToSameGroups
1764 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1765 //=======================================================================
1766
1767 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1768                                         const SMDS_MeshElement* elemInGroups,
1769                                         SMESHDS_Mesh *          aMesh)
1770 {
1771   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1772   if (!groups.empty()) {
1773     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1774     for ( ; grIt != groups.end(); grIt++ ) {
1775       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1776       if ( group && group->Contains( elemInGroups ))
1777         group->SMDSGroup().Add( elemToAdd );
1778     }
1779   }
1780 }
1781
1782
1783 //=======================================================================
1784 //function : RemoveElemFromGroups
1785 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1786 //=======================================================================
1787 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1788                                              SMESHDS_Mesh *          aMesh)
1789 {
1790   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1791   if (!groups.empty())
1792   {
1793     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1794     for (; GrIt != groups.end(); GrIt++)
1795     {
1796       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1797       if (!grp || grp->IsEmpty()) continue;
1798       grp->SMDSGroup().Remove(removeelem);
1799     }
1800   }
1801 }
1802
1803 //================================================================================
1804 /*!
1805  * \brief Replace elemToRm by elemToAdd in the all groups
1806  */
1807 //================================================================================
1808
1809 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1810                                             const SMDS_MeshElement* elemToAdd,
1811                                             SMESHDS_Mesh *          aMesh)
1812 {
1813   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1814   if (!groups.empty()) {
1815     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1816     for ( ; grIt != groups.end(); grIt++ ) {
1817       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1818       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1819         group->SMDSGroup().Add( elemToAdd );
1820     }
1821   }
1822 }
1823
1824 //================================================================================
1825 /*!
1826  * \brief Replace elemToRm by elemToAdd in the all groups
1827  */
1828 //================================================================================
1829
1830 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1831                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1832                                             SMESHDS_Mesh *                         aMesh)
1833 {
1834   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1835   if (!groups.empty())
1836   {
1837     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1838     for ( ; grIt != groups.end(); grIt++ ) {
1839       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1840       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1841         for ( int i = 0; i < elemToAdd.size(); ++i )
1842           group->SMDSGroup().Add( elemToAdd[ i ] );
1843     }
1844   }
1845 }
1846
1847 //=======================================================================
1848 //function : QuadToTri
1849 //purpose  : Cut quadrangles into triangles.
1850 //           theCrit is used to select a diagonal to cut
1851 //=======================================================================
1852
1853 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1854                                   const bool         the13Diag)
1855 {
1856   myLastCreatedElems.Clear();
1857   myLastCreatedNodes.Clear();
1858
1859   MESSAGE( "::QuadToTri()" );
1860
1861   SMESHDS_Mesh * aMesh = GetMeshDS();
1862
1863   Handle(Geom_Surface) surface;
1864   SMESH_MesherHelper   helper( *GetMesh() );
1865
1866   TIDSortedElemSet::iterator itElem;
1867   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1868     const SMDS_MeshElement* elem = *itElem;
1869     if ( !elem || elem->GetType() != SMDSAbs_Face )
1870       continue;
1871     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1872     if(!isquad) continue;
1873
1874     if(elem->NbNodes()==4) {
1875       // retrieve element nodes
1876       const SMDS_MeshNode* aNodes [4];
1877       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1878       int i = 0;
1879       while ( itN->more() )
1880         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1881
1882       int aShapeId = FindShape( elem );
1883       const SMDS_MeshElement* newElem1 = 0;
1884       const SMDS_MeshElement* newElem2 = 0;
1885       if ( the13Diag ) {
1886         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1887         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1888       }
1889       else {
1890         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1891         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1892       }
1893       myLastCreatedElems.Append(newElem1);
1894       myLastCreatedElems.Append(newElem2);
1895       // put a new triangle on the same shape and add to the same groups
1896       if ( aShapeId )
1897         {
1898           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1899           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1900         }
1901       AddToSameGroups( newElem1, elem, aMesh );
1902       AddToSameGroups( newElem2, elem, aMesh );
1903       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1904       aMesh->RemoveElement( elem );
1905     }
1906
1907     // Quadratic quadrangle
1908
1909     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1910
1911       // get surface elem is on
1912       int aShapeId = FindShape( elem );
1913       if ( aShapeId != helper.GetSubShapeID() ) {
1914         surface.Nullify();
1915         TopoDS_Shape shape;
1916         if ( aShapeId > 0 )
1917           shape = aMesh->IndexToShape( aShapeId );
1918         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1919           TopoDS_Face face = TopoDS::Face( shape );
1920           surface = BRep_Tool::Surface( face );
1921           if ( !surface.IsNull() )
1922             helper.SetSubShape( shape );
1923         }
1924       }
1925
1926       const SMDS_MeshNode* aNodes [8];
1927       const SMDS_MeshNode* inFaceNode = 0;
1928       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1929       int i = 0;
1930       while ( itN->more() ) {
1931         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1932         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1933              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1934         {
1935           inFaceNode = aNodes[ i-1 ];
1936         }
1937       }
1938
1939       // find middle point for (0,1,2,3)
1940       // and create a node in this point;
1941       gp_XYZ p( 0,0,0 );
1942       if ( surface.IsNull() ) {
1943         for(i=0; i<4; i++)
1944           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1945         p /= 4;
1946       }
1947       else {
1948         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1949         gp_XY uv( 0,0 );
1950         for(i=0; i<4; i++)
1951           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1952         uv /= 4.;
1953         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1954       }
1955       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1956       myLastCreatedNodes.Append(newN);
1957
1958       // create a new element
1959       const SMDS_MeshElement* newElem1 = 0;
1960       const SMDS_MeshElement* newElem2 = 0;
1961       const SMDS_MeshNode* N[6];
1962       if ( the13Diag ) {
1963         N[0] = aNodes[0];
1964         N[1] = aNodes[1];
1965         N[2] = aNodes[2];
1966         N[3] = aNodes[4];
1967         N[4] = aNodes[5];
1968         N[5] = newN;
1969         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1970                                   aNodes[6], aNodes[7], newN );
1971         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1972                                   newN,      aNodes[4], aNodes[5] );
1973       }
1974       else {
1975         N[0] = aNodes[1];
1976         N[1] = aNodes[2];
1977         N[2] = aNodes[3];
1978         N[3] = aNodes[5];
1979         N[4] = aNodes[6];
1980         N[5] = newN;
1981         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1982                                   aNodes[7], aNodes[4], newN );
1983         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1984                                   newN,      aNodes[5], aNodes[6] );
1985       }
1986       myLastCreatedElems.Append(newElem1);
1987       myLastCreatedElems.Append(newElem2);
1988       // put a new triangle on the same shape and add to the same groups
1989       if ( aShapeId )
1990         {
1991           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1992           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1993         }
1994       AddToSameGroups( newElem1, elem, aMesh );
1995       AddToSameGroups( newElem2, elem, aMesh );
1996       aMesh->RemoveElement( elem );
1997     }
1998   }
1999
2000   return true;
2001 }
2002
2003 //=======================================================================
2004 //function : getAngle
2005 //purpose  :
2006 //=======================================================================
2007
2008 double getAngle(const SMDS_MeshElement * tr1,
2009                 const SMDS_MeshElement * tr2,
2010                 const SMDS_MeshNode *    n1,
2011                 const SMDS_MeshNode *    n2)
2012 {
2013   double angle = 2*PI; // bad angle
2014
2015   // get normals
2016   SMESH::Controls::TSequenceOfXYZ P1, P2;
2017   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2018        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2019     return angle;
2020   gp_Vec N1,N2;
2021   if(!tr1->IsQuadratic())
2022     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2023   else
2024     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2025   if ( N1.SquareMagnitude() <= gp::Resolution() )
2026     return angle;
2027   if(!tr2->IsQuadratic())
2028     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2029   else
2030     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2031   if ( N2.SquareMagnitude() <= gp::Resolution() )
2032     return angle;
2033
2034   // find the first diagonal node n1 in the triangles:
2035   // take in account a diagonal link orientation
2036   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2037   for ( int t = 0; t < 2; t++ ) {
2038     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2039     int i = 0, iDiag = -1;
2040     while ( it->more()) {
2041       const SMDS_MeshElement *n = it->next();
2042       if ( n == n1 || n == n2 ) {
2043         if ( iDiag < 0)
2044           iDiag = i;
2045         else {
2046           if ( i - iDiag == 1 )
2047             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2048           else
2049             nFirst[ t ] = n;
2050           break;
2051         }
2052       }
2053       i++;
2054     }
2055   }
2056   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2057     N2.Reverse();
2058
2059   angle = N1.Angle( N2 );
2060   //SCRUTE( angle );
2061   return angle;
2062 }
2063
2064 // =================================================
2065 // class generating a unique ID for a pair of nodes
2066 // and able to return nodes by that ID
2067 // =================================================
2068 class LinkID_Gen {
2069 public:
2070
2071   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2072     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2073   {}
2074
2075   long GetLinkID (const SMDS_MeshNode * n1,
2076                   const SMDS_MeshNode * n2) const
2077   {
2078     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2079   }
2080
2081   bool GetNodes (const long             theLinkID,
2082                  const SMDS_MeshNode* & theNode1,
2083                  const SMDS_MeshNode* & theNode2) const
2084   {
2085     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2086     if ( !theNode1 ) return false;
2087     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2088     if ( !theNode2 ) return false;
2089     return true;
2090   }
2091
2092 private:
2093   LinkID_Gen();
2094   const SMESHDS_Mesh* myMesh;
2095   long                myMaxID;
2096 };
2097
2098
2099 //=======================================================================
2100 //function : TriToQuad
2101 //purpose  : Fuse neighbour triangles into quadrangles.
2102 //           theCrit is used to select a neighbour to fuse with.
2103 //           theMaxAngle is a max angle between element normals at which
2104 //           fusion is still performed.
2105 //=======================================================================
2106
2107 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2108                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2109                                   const double                         theMaxAngle)
2110 {
2111   myLastCreatedElems.Clear();
2112   myLastCreatedNodes.Clear();
2113
2114   MESSAGE( "::TriToQuad()" );
2115
2116   if ( !theCrit.get() )
2117     return false;
2118
2119   SMESHDS_Mesh * aMesh = GetMeshDS();
2120
2121   // Prepare data for algo: build
2122   // 1. map of elements with their linkIDs
2123   // 2. map of linkIDs with their elements
2124
2125   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2126   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2127   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2128   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2129
2130   TIDSortedElemSet::iterator itElem;
2131   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2132     const SMDS_MeshElement* elem = *itElem;
2133     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2134     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2135     if(!IsTria) continue;
2136
2137     // retrieve element nodes
2138     const SMDS_MeshNode* aNodes [4];
2139     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2140     int i = 0;
2141     while ( i<3 )
2142       aNodes[ i++ ] = cast2Node( itN->next() );
2143     aNodes[ 3 ] = aNodes[ 0 ];
2144
2145     // fill maps
2146     for ( i = 0; i < 3; i++ ) {
2147       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2148       // check if elements sharing a link can be fused
2149       itLE = mapLi_listEl.find( link );
2150       if ( itLE != mapLi_listEl.end() ) {
2151         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2152           continue;
2153         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2154         //if ( FindShape( elem ) != FindShape( elem2 ))
2155         //  continue; // do not fuse triangles laying on different shapes
2156         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2157           continue; // avoid making badly shaped quads
2158         (*itLE).second.push_back( elem );
2159       }
2160       else {
2161         mapLi_listEl[ link ].push_back( elem );
2162       }
2163       mapEl_setLi [ elem ].insert( link );
2164     }
2165   }
2166   // Clean the maps from the links shared by a sole element, ie
2167   // links to which only one element is bound in mapLi_listEl
2168
2169   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2170     int nbElems = (*itLE).second.size();
2171     if ( nbElems < 2  ) {
2172       const SMDS_MeshElement* elem = (*itLE).second.front();
2173       SMESH_TLink link = (*itLE).first;
2174       mapEl_setLi[ elem ].erase( link );
2175       if ( mapEl_setLi[ elem ].empty() )
2176         mapEl_setLi.erase( elem );
2177     }
2178   }
2179
2180   // Algo: fuse triangles into quadrangles
2181
2182   while ( ! mapEl_setLi.empty() ) {
2183     // Look for the start element:
2184     // the element having the least nb of shared links
2185     const SMDS_MeshElement* startElem = 0;
2186     int minNbLinks = 4;
2187     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2188       int nbLinks = (*itEL).second.size();
2189       if ( nbLinks < minNbLinks ) {
2190         startElem = (*itEL).first;
2191         minNbLinks = nbLinks;
2192         if ( minNbLinks == 1 )
2193           break;
2194       }
2195     }
2196
2197     // search elements to fuse starting from startElem or links of elements
2198     // fused earlyer - startLinks
2199     list< SMESH_TLink > startLinks;
2200     while ( startElem || !startLinks.empty() ) {
2201       while ( !startElem && !startLinks.empty() ) {
2202         // Get an element to start, by a link
2203         SMESH_TLink linkId = startLinks.front();
2204         startLinks.pop_front();
2205         itLE = mapLi_listEl.find( linkId );
2206         if ( itLE != mapLi_listEl.end() ) {
2207           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2208           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2209           for ( ; itE != listElem.end() ; itE++ )
2210             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2211               startElem = (*itE);
2212           mapLi_listEl.erase( itLE );
2213         }
2214       }
2215
2216       if ( startElem ) {
2217         // Get candidates to be fused
2218         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2219         const SMESH_TLink *link12, *link13;
2220         startElem = 0;
2221         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2222         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2223         ASSERT( !setLi.empty() );
2224         set< SMESH_TLink >::iterator itLi;
2225         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2226         {
2227           const SMESH_TLink & link = (*itLi);
2228           itLE = mapLi_listEl.find( link );
2229           if ( itLE == mapLi_listEl.end() )
2230             continue;
2231
2232           const SMDS_MeshElement* elem = (*itLE).second.front();
2233           if ( elem == tr1 )
2234             elem = (*itLE).second.back();
2235           mapLi_listEl.erase( itLE );
2236           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2237             continue;
2238           if ( tr2 ) {
2239             tr3 = elem;
2240             link13 = &link;
2241           }
2242           else {
2243             tr2 = elem;
2244             link12 = &link;
2245           }
2246
2247           // add other links of elem to list of links to re-start from
2248           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2249           set< SMESH_TLink >::iterator it;
2250           for ( it = links.begin(); it != links.end(); it++ ) {
2251             const SMESH_TLink& link2 = (*it);
2252             if ( link2 != link )
2253               startLinks.push_back( link2 );
2254           }
2255         }
2256
2257         // Get nodes of possible quadrangles
2258         const SMDS_MeshNode *n12 [4], *n13 [4];
2259         bool Ok12 = false, Ok13 = false;
2260         const SMDS_MeshNode *linkNode1, *linkNode2;
2261         if(tr2) {
2262           linkNode1 = link12->first;
2263           linkNode2 = link12->second;
2264           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2265             Ok12 = true;
2266         }
2267         if(tr3) {
2268           linkNode1 = link13->first;
2269           linkNode2 = link13->second;
2270           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2271             Ok13 = true;
2272         }
2273
2274         // Choose a pair to fuse
2275         if ( Ok12 && Ok13 ) {
2276           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2277           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2278           double aBadRate12 = getBadRate( &quad12, theCrit );
2279           double aBadRate13 = getBadRate( &quad13, theCrit );
2280           if (  aBadRate13 < aBadRate12 )
2281             Ok12 = false;
2282           else
2283             Ok13 = false;
2284         }
2285
2286         // Make quadrangles
2287         // and remove fused elems and removed links from the maps
2288         mapEl_setLi.erase( tr1 );
2289         if ( Ok12 ) {
2290           mapEl_setLi.erase( tr2 );
2291           mapLi_listEl.erase( *link12 );
2292           if(tr1->NbNodes()==3) {
2293             const SMDS_MeshElement* newElem = 0;
2294             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2295             myLastCreatedElems.Append(newElem);
2296             AddToSameGroups( newElem, tr1, aMesh );
2297             int aShapeId = tr1->getshapeId();
2298             if ( aShapeId )
2299               {
2300                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2301               }
2302             aMesh->RemoveElement( tr1 );
2303             aMesh->RemoveElement( tr2 );
2304           }
2305           else {
2306             const SMDS_MeshNode* N1 [6];
2307             const SMDS_MeshNode* N2 [6];
2308             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2309             // now we receive following N1 and N2 (using numeration as above image)
2310             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2311             // i.e. first nodes from both arrays determ new diagonal
2312             const SMDS_MeshNode* aNodes[8];
2313             aNodes[0] = N1[0];
2314             aNodes[1] = N1[1];
2315             aNodes[2] = N2[0];
2316             aNodes[3] = N2[1];
2317             aNodes[4] = N1[3];
2318             aNodes[5] = N2[5];
2319             aNodes[6] = N2[3];
2320             aNodes[7] = N1[5];
2321             const SMDS_MeshElement* newElem = 0;
2322             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2323                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2324             myLastCreatedElems.Append(newElem);
2325             AddToSameGroups( newElem, tr1, aMesh );
2326             int aShapeId = tr1->getshapeId();
2327             if ( aShapeId )
2328               {
2329                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2330               }
2331             aMesh->RemoveElement( tr1 );
2332             aMesh->RemoveElement( tr2 );
2333             // remove middle node (9)
2334             GetMeshDS()->RemoveNode( N1[4] );
2335           }
2336         }
2337         else if ( Ok13 ) {
2338           mapEl_setLi.erase( tr3 );
2339           mapLi_listEl.erase( *link13 );
2340           if(tr1->NbNodes()==3) {
2341             const SMDS_MeshElement* newElem = 0;
2342             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2343             myLastCreatedElems.Append(newElem);
2344             AddToSameGroups( newElem, tr1, aMesh );
2345             int aShapeId = tr1->getshapeId();
2346             if ( aShapeId )
2347               {
2348                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2349               }
2350             aMesh->RemoveElement( tr1 );
2351             aMesh->RemoveElement( tr3 );
2352           }
2353           else {
2354             const SMDS_MeshNode* N1 [6];
2355             const SMDS_MeshNode* N2 [6];
2356             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2357             // now we receive following N1 and N2 (using numeration as above image)
2358             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2359             // i.e. first nodes from both arrays determ new diagonal
2360             const SMDS_MeshNode* aNodes[8];
2361             aNodes[0] = N1[0];
2362             aNodes[1] = N1[1];
2363             aNodes[2] = N2[0];
2364             aNodes[3] = N2[1];
2365             aNodes[4] = N1[3];
2366             aNodes[5] = N2[5];
2367             aNodes[6] = N2[3];
2368             aNodes[7] = N1[5];
2369             const SMDS_MeshElement* newElem = 0;
2370             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2371                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2372             myLastCreatedElems.Append(newElem);
2373             AddToSameGroups( newElem, tr1, aMesh );
2374             int aShapeId = tr1->getshapeId();
2375             if ( aShapeId )
2376               {
2377                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2378               }
2379             aMesh->RemoveElement( tr1 );
2380             aMesh->RemoveElement( tr3 );
2381             // remove middle node (9)
2382             GetMeshDS()->RemoveNode( N1[4] );
2383           }
2384         }
2385
2386         // Next element to fuse: the rejected one
2387         if ( tr3 )
2388           startElem = Ok12 ? tr3 : tr2;
2389
2390       } // if ( startElem )
2391     } // while ( startElem || !startLinks.empty() )
2392   } // while ( ! mapEl_setLi.empty() )
2393
2394   return true;
2395 }
2396
2397
2398 /*#define DUMPSO(txt) \
2399 //  cout << txt << endl;
2400 //=============================================================================
2401 //
2402 //
2403 //
2404 //=============================================================================
2405 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2406 {
2407 if ( i1 == i2 )
2408 return;
2409 int tmp = idNodes[ i1 ];
2410 idNodes[ i1 ] = idNodes[ i2 ];
2411 idNodes[ i2 ] = tmp;
2412 gp_Pnt Ptmp = P[ i1 ];
2413 P[ i1 ] = P[ i2 ];
2414 P[ i2 ] = Ptmp;
2415 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2416 }
2417
2418 //=======================================================================
2419 //function : SortQuadNodes
2420 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2421 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2422 //           1 or 2 else 0.
2423 //=======================================================================
2424
2425 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2426 int               idNodes[] )
2427 {
2428   gp_Pnt P[4];
2429   int i;
2430   for ( i = 0; i < 4; i++ ) {
2431     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2432     if ( !n ) return 0;
2433     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2434   }
2435
2436   gp_Vec V1(P[0], P[1]);
2437   gp_Vec V2(P[0], P[2]);
2438   gp_Vec V3(P[0], P[3]);
2439
2440   gp_Vec Cross1 = V1 ^ V2;
2441   gp_Vec Cross2 = V2 ^ V3;
2442
2443   i = 0;
2444   if (Cross1.Dot(Cross2) < 0)
2445   {
2446     Cross1 = V2 ^ V1;
2447     Cross2 = V1 ^ V3;
2448
2449     if (Cross1.Dot(Cross2) < 0)
2450       i = 2;
2451     else
2452       i = 1;
2453     swap ( i, i + 1, idNodes, P );
2454
2455     //     for ( int ii = 0; ii < 4; ii++ ) {
2456     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2457     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2458     //     }
2459   }
2460   return i;
2461 }
2462
2463 //=======================================================================
2464 //function : SortHexaNodes
2465 //purpose  : Set 8 nodes of a hexahedron in a good order.
2466 //           Return success status
2467 //=======================================================================
2468
2469 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2470                                       int               idNodes[] )
2471 {
2472   gp_Pnt P[8];
2473   int i;
2474   DUMPSO( "INPUT: ========================================");
2475   for ( i = 0; i < 8; i++ ) {
2476     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2477     if ( !n ) return false;
2478     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2479     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2480   }
2481   DUMPSO( "========================================");
2482
2483
2484   set<int> faceNodes;  // ids of bottom face nodes, to be found
2485   set<int> checkedId1; // ids of tried 2-nd nodes
2486   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2487   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2488   int iMin, iLoop1 = 0;
2489
2490   // Loop to try the 2-nd nodes
2491
2492   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2493   {
2494     // Find not checked 2-nd node
2495     for ( i = 1; i < 8; i++ )
2496       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2497         int id1 = idNodes[i];
2498         swap ( 1, i, idNodes, P );
2499         checkedId1.insert ( id1 );
2500         break;
2501       }
2502
2503     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2504     // ie that all but meybe one (id3 which is on the same face) nodes
2505     // lay on the same side from the triangle plane.
2506
2507     bool manyInPlane = false; // more than 4 nodes lay in plane
2508     int iLoop2 = 0;
2509     while ( ++iLoop2 < 6 ) {
2510
2511       // get 1-2-3 plane coeffs
2512       Standard_Real A, B, C, D;
2513       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2514       if ( N.SquareMagnitude() > gp::Resolution() )
2515       {
2516         gp_Pln pln ( P[0], N );
2517         pln.Coefficients( A, B, C, D );
2518
2519         // find the node (iMin) closest to pln
2520         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2521         set<int> idInPln;
2522         for ( i = 3; i < 8; i++ ) {
2523           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2524           if ( fabs( dist[i] ) < minDist ) {
2525             minDist = fabs( dist[i] );
2526             iMin = i;
2527           }
2528           if ( fabs( dist[i] ) <= tol )
2529             idInPln.insert( idNodes[i] );
2530         }
2531
2532         // there should not be more than 4 nodes in bottom plane
2533         if ( idInPln.size() > 1 )
2534         {
2535           DUMPSO( "### idInPln.size() = " << idInPln.size());
2536           // idInPlane does not contain the first 3 nodes
2537           if ( manyInPlane || idInPln.size() == 5)
2538             return false; // all nodes in one plane
2539           manyInPlane = true;
2540
2541           // set the 1-st node to be not in plane
2542           for ( i = 3; i < 8; i++ ) {
2543             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2544               DUMPSO( "### Reset 0-th node");
2545               swap( 0, i, idNodes, P );
2546               break;
2547             }
2548           }
2549
2550           // reset to re-check second nodes
2551           leastDist = DBL_MAX;
2552           faceNodes.clear();
2553           checkedId1.clear();
2554           iLoop1 = 0;
2555           break; // from iLoop2;
2556         }
2557
2558         // check that the other 4 nodes are on the same side
2559         bool sameSide = true;
2560         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2561         for ( i = 3; sameSide && i < 8; i++ ) {
2562           if ( i != iMin )
2563             sameSide = ( isNeg == dist[i] <= 0.);
2564         }
2565
2566         // keep best solution
2567         if ( sameSide && minDist < leastDist ) {
2568           leastDist = minDist;
2569           faceNodes.clear();
2570           faceNodes.insert( idNodes[ 1 ] );
2571           faceNodes.insert( idNodes[ 2 ] );
2572           faceNodes.insert( idNodes[ iMin ] );
2573           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2574                   << " leastDist = " << leastDist);
2575           if ( leastDist <= DBL_MIN )
2576             break;
2577         }
2578       }
2579
2580       // set next 3-d node to check
2581       int iNext = 2 + iLoop2;
2582       if ( iNext < 8 ) {
2583         DUMPSO( "Try 2-nd");
2584         swap ( 2, iNext, idNodes, P );
2585       }
2586     } // while ( iLoop2 < 6 )
2587   } // iLoop1
2588
2589   if ( faceNodes.empty() ) return false;
2590
2591   // Put the faceNodes in proper places
2592   for ( i = 4; i < 8; i++ ) {
2593     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2594       // find a place to put
2595       int iTo = 1;
2596       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2597         iTo++;
2598       DUMPSO( "Set faceNodes");
2599       swap ( iTo, i, idNodes, P );
2600     }
2601   }
2602
2603
2604   // Set nodes of the found bottom face in good order
2605   DUMPSO( " Found bottom face: ");
2606   i = SortQuadNodes( theMesh, idNodes );
2607   if ( i ) {
2608     gp_Pnt Ptmp = P[ i ];
2609     P[ i ] = P[ i+1 ];
2610     P[ i+1 ] = Ptmp;
2611   }
2612   //   else
2613   //     for ( int ii = 0; ii < 4; ii++ ) {
2614   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2615   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2616   //    }
2617
2618   // Gravity center of the top and bottom faces
2619   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2620   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2621
2622   // Get direction from the bottom to the top face
2623   gp_Vec upDir ( aGCb, aGCt );
2624   Standard_Real upDirSize = upDir.Magnitude();
2625   if ( upDirSize <= gp::Resolution() ) return false;
2626   upDir / upDirSize;
2627
2628   // Assure that the bottom face normal points up
2629   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2630   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2631   if ( Nb.Dot( upDir ) < 0 ) {
2632     DUMPSO( "Reverse bottom face");
2633     swap( 1, 3, idNodes, P );
2634   }
2635
2636   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2637   Standard_Real minDist = DBL_MAX;
2638   for ( i = 4; i < 8; i++ ) {
2639     // projection of P[i] to the plane defined by P[0] and upDir
2640     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2641     Standard_Real sqDist = P[0].SquareDistance( Pp );
2642     if ( sqDist < minDist ) {
2643       minDist = sqDist;
2644       iMin = i;
2645     }
2646   }
2647   DUMPSO( "Set 4-th");
2648   swap ( 4, iMin, idNodes, P );
2649
2650   // Set nodes of the top face in good order
2651   DUMPSO( "Sort top face");
2652   i = SortQuadNodes( theMesh, &idNodes[4] );
2653   if ( i ) {
2654     i += 4;
2655     gp_Pnt Ptmp = P[ i ];
2656     P[ i ] = P[ i+1 ];
2657     P[ i+1 ] = Ptmp;
2658   }
2659
2660   // Assure that direction of the top face normal is from the bottom face
2661   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2662   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2663   if ( Nt.Dot( upDir ) < 0 ) {
2664     DUMPSO( "Reverse top face");
2665     swap( 5, 7, idNodes, P );
2666   }
2667
2668   //   DUMPSO( "OUTPUT: ========================================");
2669   //   for ( i = 0; i < 8; i++ ) {
2670   //     float *p = ugrid->GetPoint(idNodes[i]);
2671   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2672   //   }
2673
2674   return true;
2675 }*/
2676
2677 //================================================================================
2678 /*!
2679  * \brief Return nodes linked to the given one
2680  * \param theNode - the node
2681  * \param linkedNodes - the found nodes
2682  * \param type - the type of elements to check
2683  *
2684  * Medium nodes are ignored
2685  */
2686 //================================================================================
2687
2688 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2689                                        TIDSortedElemSet &   linkedNodes,
2690                                        SMDSAbs_ElementType  type )
2691 {
2692   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2693   while ( elemIt->more() )
2694   {
2695     const SMDS_MeshElement* elem = elemIt->next();
2696     if(elem->GetType() == SMDSAbs_0DElement)
2697       continue;
2698     
2699     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2700     if ( elem->GetType() == SMDSAbs_Volume )
2701     {
2702       SMDS_VolumeTool vol( elem );
2703       while ( nodeIt->more() ) {
2704         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2705         if ( theNode != n && vol.IsLinked( theNode, n ))
2706           linkedNodes.insert( n );
2707       }
2708     }
2709     else
2710     {
2711       for ( int i = 0; nodeIt->more(); ++i ) {
2712         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2713         if ( n == theNode ) {
2714           int iBefore = i - 1;
2715           int iAfter  = i + 1;
2716           if ( elem->IsQuadratic() ) {
2717             int nb = elem->NbNodes() / 2;
2718             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2719             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2720           }
2721           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2722           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2723         }
2724       }
2725     }
2726   }
2727 }
2728
2729 //=======================================================================
2730 //function : laplacianSmooth
2731 //purpose  : pulls theNode toward the center of surrounding nodes directly
2732 //           connected to that node along an element edge
2733 //=======================================================================
2734
2735 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2736                      const Handle(Geom_Surface)&          theSurface,
2737                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2738 {
2739   // find surrounding nodes
2740
2741   TIDSortedElemSet nodeSet;
2742   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2743
2744   // compute new coodrs
2745
2746   double coord[] = { 0., 0., 0. };
2747   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2748   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2749     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2750     if ( theSurface.IsNull() ) { // smooth in 3D
2751       coord[0] += node->X();
2752       coord[1] += node->Y();
2753       coord[2] += node->Z();
2754     }
2755     else { // smooth in 2D
2756       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2757       gp_XY* uv = theUVMap[ node ];
2758       coord[0] += uv->X();
2759       coord[1] += uv->Y();
2760     }
2761   }
2762   int nbNodes = nodeSet.size();
2763   if ( !nbNodes )
2764     return;
2765   coord[0] /= nbNodes;
2766   coord[1] /= nbNodes;
2767
2768   if ( !theSurface.IsNull() ) {
2769     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2770     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2771     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2772     coord[0] = p3d.X();
2773     coord[1] = p3d.Y();
2774     coord[2] = p3d.Z();
2775   }
2776   else
2777     coord[2] /= nbNodes;
2778
2779   // move node
2780
2781   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2782 }
2783
2784 //=======================================================================
2785 //function : centroidalSmooth
2786 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2787 //           surrounding elements
2788 //=======================================================================
2789
2790 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2791                       const Handle(Geom_Surface)&          theSurface,
2792                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2793 {
2794   gp_XYZ aNewXYZ(0.,0.,0.);
2795   SMESH::Controls::Area anAreaFunc;
2796   double totalArea = 0.;
2797   int nbElems = 0;
2798
2799   // compute new XYZ
2800
2801   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2802   while ( elemIt->more() )
2803   {
2804     const SMDS_MeshElement* elem = elemIt->next();
2805     nbElems++;
2806
2807     gp_XYZ elemCenter(0.,0.,0.);
2808     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2809     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2810     int nn = elem->NbNodes();
2811     if(elem->IsQuadratic()) nn = nn/2;
2812     int i=0;
2813     //while ( itN->more() ) {
2814     while ( i<nn ) {
2815       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2816       i++;
2817       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2818       aNodePoints.push_back( aP );
2819       if ( !theSurface.IsNull() ) { // smooth in 2D
2820         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2821         gp_XY* uv = theUVMap[ aNode ];
2822         aP.SetCoord( uv->X(), uv->Y(), 0. );
2823       }
2824       elemCenter += aP;
2825     }
2826     double elemArea = anAreaFunc.GetValue( aNodePoints );
2827     totalArea += elemArea;
2828     elemCenter /= nn;
2829     aNewXYZ += elemCenter * elemArea;
2830   }
2831   aNewXYZ /= totalArea;
2832   if ( !theSurface.IsNull() ) {
2833     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2834     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2835   }
2836
2837   // move node
2838
2839   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2840 }
2841
2842 //=======================================================================
2843 //function : getClosestUV
2844 //purpose  : return UV of closest projection
2845 //=======================================================================
2846
2847 static bool getClosestUV (Extrema_GenExtPS& projector,
2848                           const gp_Pnt&     point,
2849                           gp_XY &           result)
2850 {
2851   projector.Perform( point );
2852   if ( projector.IsDone() ) {
2853     double u, v, minVal = DBL_MAX;
2854     for ( int i = projector.NbExt(); i > 0; i-- )
2855       if ( projector.Value( i ) < minVal ) {
2856         minVal = projector.Value( i );
2857         projector.Point( i ).Parameter( u, v );
2858       }
2859     result.SetCoord( u, v );
2860     return true;
2861   }
2862   return false;
2863 }
2864
2865 //=======================================================================
2866 //function : Smooth
2867 //purpose  : Smooth theElements during theNbIterations or until a worst
2868 //           element has aspect ratio <= theTgtAspectRatio.
2869 //           Aspect Ratio varies in range [1.0, inf].
2870 //           If theElements is empty, the whole mesh is smoothed.
2871 //           theFixedNodes contains additionally fixed nodes. Nodes built
2872 //           on edges and boundary nodes are always fixed.
2873 //=======================================================================
2874
2875 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2876                                set<const SMDS_MeshNode*> & theFixedNodes,
2877                                const SmoothMethod          theSmoothMethod,
2878                                const int                   theNbIterations,
2879                                double                      theTgtAspectRatio,
2880                                const bool                  the2D)
2881 {
2882   myLastCreatedElems.Clear();
2883   myLastCreatedNodes.Clear();
2884
2885   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2886
2887   if ( theTgtAspectRatio < 1.0 )
2888     theTgtAspectRatio = 1.0;
2889
2890   const double disttol = 1.e-16;
2891
2892   SMESH::Controls::AspectRatio aQualityFunc;
2893
2894   SMESHDS_Mesh* aMesh = GetMeshDS();
2895
2896   if ( theElems.empty() ) {
2897     // add all faces to theElems
2898     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2899     while ( fIt->more() ) {
2900       const SMDS_MeshElement* face = fIt->next();
2901       theElems.insert( face );
2902     }
2903   }
2904   // get all face ids theElems are on
2905   set< int > faceIdSet;
2906   TIDSortedElemSet::iterator itElem;
2907   if ( the2D )
2908     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2909       int fId = FindShape( *itElem );
2910       // check that corresponding submesh exists and a shape is face
2911       if (fId &&
2912           faceIdSet.find( fId ) == faceIdSet.end() &&
2913           aMesh->MeshElements( fId )) {
2914         TopoDS_Shape F = aMesh->IndexToShape( fId );
2915         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2916           faceIdSet.insert( fId );
2917       }
2918     }
2919   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2920
2921   // ===============================================
2922   // smooth elements on each TopoDS_Face separately
2923   // ===============================================
2924
2925   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2926   for ( ; fId != faceIdSet.rend(); ++fId ) {
2927     // get face surface and submesh
2928     Handle(Geom_Surface) surface;
2929     SMESHDS_SubMesh* faceSubMesh = 0;
2930     TopoDS_Face face;
2931     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2932     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2933     bool isUPeriodic = false, isVPeriodic = false;
2934     if ( *fId ) {
2935       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2936       surface = BRep_Tool::Surface( face );
2937       faceSubMesh = aMesh->MeshElements( *fId );
2938       fToler2 = BRep_Tool::Tolerance( face );
2939       fToler2 *= fToler2 * 10.;
2940       isUPeriodic = surface->IsUPeriodic();
2941       if ( isUPeriodic )
2942         vPeriod = surface->UPeriod();
2943       isVPeriodic = surface->IsVPeriodic();
2944       if ( isVPeriodic )
2945         uPeriod = surface->VPeriod();
2946       surface->Bounds( u1, u2, v1, v2 );
2947     }
2948     // ---------------------------------------------------------
2949     // for elements on a face, find movable and fixed nodes and
2950     // compute UV for them
2951     // ---------------------------------------------------------
2952     bool checkBoundaryNodes = false;
2953     bool isQuadratic = false;
2954     set<const SMDS_MeshNode*> setMovableNodes;
2955     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2956     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2957     list< const SMDS_MeshElement* > elemsOnFace;
2958
2959     Extrema_GenExtPS projector;
2960     GeomAdaptor_Surface surfAdaptor;
2961     if ( !surface.IsNull() ) {
2962       surfAdaptor.Load( surface );
2963       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2964     }
2965     int nbElemOnFace = 0;
2966     itElem = theElems.begin();
2967     // loop on not yet smoothed elements: look for elems on a face
2968     while ( itElem != theElems.end() ) {
2969       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2970         break; // all elements found
2971
2972       const SMDS_MeshElement* elem = *itElem;
2973       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2974            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2975         ++itElem;
2976         continue;
2977       }
2978       elemsOnFace.push_back( elem );
2979       theElems.erase( itElem++ );
2980       nbElemOnFace++;
2981
2982       if ( !isQuadratic )
2983         isQuadratic = elem->IsQuadratic();
2984
2985       // get movable nodes of elem
2986       const SMDS_MeshNode* node;
2987       SMDS_TypeOfPosition posType;
2988       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2989       int nn = 0, nbn =  elem->NbNodes();
2990       if(elem->IsQuadratic())
2991         nbn = nbn/2;
2992       while ( nn++ < nbn ) {
2993         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2994         const SMDS_PositionPtr& pos = node->GetPosition();
2995         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2996         if (posType != SMDS_TOP_EDGE &&
2997             posType != SMDS_TOP_VERTEX &&
2998             theFixedNodes.find( node ) == theFixedNodes.end())
2999         {
3000           // check if all faces around the node are on faceSubMesh
3001           // because a node on edge may be bound to face
3002           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3003           bool all = true;
3004           if ( faceSubMesh ) {
3005             while ( eIt->more() && all ) {
3006               const SMDS_MeshElement* e = eIt->next();
3007               all = faceSubMesh->Contains( e );
3008             }
3009           }
3010           if ( all )
3011             setMovableNodes.insert( node );
3012           else
3013             checkBoundaryNodes = true;
3014         }
3015         if ( posType == SMDS_TOP_3DSPACE )
3016           checkBoundaryNodes = true;
3017       }
3018
3019       if ( surface.IsNull() )
3020         continue;
3021
3022       // get nodes to check UV
3023       list< const SMDS_MeshNode* > uvCheckNodes;
3024       itN = elem->nodesIterator();
3025       nn = 0; nbn =  elem->NbNodes();
3026       if(elem->IsQuadratic())
3027         nbn = nbn/2;
3028       while ( nn++ < nbn ) {
3029         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3030         if ( uvMap.find( node ) == uvMap.end() )
3031           uvCheckNodes.push_back( node );
3032         // add nodes of elems sharing node
3033         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3034         //         while ( eIt->more() ) {
3035         //           const SMDS_MeshElement* e = eIt->next();
3036         //           if ( e != elem ) {
3037         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3038         //             while ( nIt->more() ) {
3039         //               const SMDS_MeshNode* n =
3040         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3041         //               if ( uvMap.find( n ) == uvMap.end() )
3042         //                 uvCheckNodes.push_back( n );
3043         //             }
3044         //           }
3045         //         }
3046       }
3047       // check UV on face
3048       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3049       for ( ; n != uvCheckNodes.end(); ++n ) {
3050         node = *n;
3051         gp_XY uv( 0, 0 );
3052         const SMDS_PositionPtr& pos = node->GetPosition();
3053         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3054         // get existing UV
3055         switch ( posType ) {
3056         case SMDS_TOP_FACE: {
3057           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3058           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3059           break;
3060         }
3061         case SMDS_TOP_EDGE: {
3062           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3063           Handle(Geom2d_Curve) pcurve;
3064           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3065             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3066           if ( !pcurve.IsNull() ) {
3067             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3068             uv = pcurve->Value( u ).XY();
3069           }
3070           break;
3071         }
3072         case SMDS_TOP_VERTEX: {
3073           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3074           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3075             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3076           break;
3077         }
3078         default:;
3079         }
3080         // check existing UV
3081         bool project = true;
3082         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3083         double dist1 = DBL_MAX, dist2 = 0;
3084         if ( posType != SMDS_TOP_3DSPACE ) {
3085           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3086           project = dist1 > fToler2;
3087         }
3088         if ( project ) { // compute new UV
3089           gp_XY newUV;
3090           if ( !getClosestUV( projector, pNode, newUV )) {
3091             MESSAGE("Node Projection Failed " << node);
3092           }
3093           else {
3094             if ( isUPeriodic )
3095               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3096             if ( isVPeriodic )
3097               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3098             // check new UV
3099             if ( posType != SMDS_TOP_3DSPACE )
3100               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3101             if ( dist2 < dist1 )
3102               uv = newUV;
3103           }
3104         }
3105         // store UV in the map
3106         listUV.push_back( uv );
3107         uvMap.insert( make_pair( node, &listUV.back() ));
3108       }
3109     } // loop on not yet smoothed elements
3110
3111     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3112       checkBoundaryNodes = true;
3113
3114     // fix nodes on mesh boundary
3115
3116     if ( checkBoundaryNodes ) {
3117       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3118       map< NLink, int >::iterator link_nb;
3119       // put all elements links to linkNbMap
3120       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3121       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3122         const SMDS_MeshElement* elem = (*elemIt);
3123         int nbn =  elem->NbNodes();
3124         if(elem->IsQuadratic())
3125           nbn = nbn/2;
3126         // loop on elem links: insert them in linkNbMap
3127         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3128         for ( int iN = 0; iN < nbn; ++iN ) {
3129           curNode = elem->GetNode( iN );
3130           NLink link;
3131           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3132           else                      link = make_pair( prevNode , curNode );
3133           prevNode = curNode;
3134           link_nb = linkNbMap.find( link );
3135           if ( link_nb == linkNbMap.end() )
3136             linkNbMap.insert( make_pair ( link, 1 ));
3137           else
3138             link_nb->second++;
3139         }
3140       }
3141       // remove nodes that are in links encountered only once from setMovableNodes
3142       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3143         if ( link_nb->second == 1 ) {
3144           setMovableNodes.erase( link_nb->first.first );
3145           setMovableNodes.erase( link_nb->first.second );
3146         }
3147       }
3148     }
3149
3150     // -----------------------------------------------------
3151     // for nodes on seam edge, compute one more UV ( uvMap2 );
3152     // find movable nodes linked to nodes on seam and which
3153     // are to be smoothed using the second UV ( uvMap2 )
3154     // -----------------------------------------------------
3155
3156     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3157     if ( !surface.IsNull() ) {
3158       TopExp_Explorer eExp( face, TopAbs_EDGE );
3159       for ( ; eExp.More(); eExp.Next() ) {
3160         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3161         if ( !BRep_Tool::IsClosed( edge, face ))
3162           continue;
3163         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3164         if ( !sm ) continue;
3165         // find out which parameter varies for a node on seam
3166         double f,l;
3167         gp_Pnt2d uv1, uv2;
3168         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3169         if ( pcurve.IsNull() ) continue;
3170         uv1 = pcurve->Value( f );
3171         edge.Reverse();
3172         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3173         if ( pcurve.IsNull() ) continue;
3174         uv2 = pcurve->Value( f );
3175         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3176         // assure uv1 < uv2
3177         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3178           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3179         }
3180         // get nodes on seam and its vertices
3181         list< const SMDS_MeshNode* > seamNodes;
3182         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3183         while ( nSeamIt->more() ) {
3184           const SMDS_MeshNode* node = nSeamIt->next();
3185           if ( !isQuadratic || !IsMedium( node ))
3186             seamNodes.push_back( node );
3187         }
3188         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3189         for ( ; vExp.More(); vExp.Next() ) {
3190           sm = aMesh->MeshElements( vExp.Current() );
3191           if ( sm ) {
3192             nSeamIt = sm->GetNodes();
3193             while ( nSeamIt->more() )
3194               seamNodes.push_back( nSeamIt->next() );
3195           }
3196         }
3197         // loop on nodes on seam
3198         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3199         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3200           const SMDS_MeshNode* nSeam = *noSeIt;
3201           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3202           if ( n_uv == uvMap.end() )
3203             continue;
3204           // set the first UV
3205           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3206           // set the second UV
3207           listUV.push_back( *n_uv->second );
3208           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3209           if ( uvMap2.empty() )
3210             uvMap2 = uvMap; // copy the uvMap contents
3211           uvMap2[ nSeam ] = &listUV.back();
3212
3213           // collect movable nodes linked to ones on seam in nodesNearSeam
3214           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3215           while ( eIt->more() ) {
3216             const SMDS_MeshElement* e = eIt->next();
3217             int nbUseMap1 = 0, nbUseMap2 = 0;
3218             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3219             int nn = 0, nbn =  e->NbNodes();
3220             if(e->IsQuadratic()) nbn = nbn/2;
3221             while ( nn++ < nbn )
3222             {
3223               const SMDS_MeshNode* n =
3224                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3225               if (n == nSeam ||
3226                   setMovableNodes.find( n ) == setMovableNodes.end() )
3227                 continue;
3228               // add only nodes being closer to uv2 than to uv1
3229               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3230                            0.5 * ( n->Y() + nSeam->Y() ),
3231                            0.5 * ( n->Z() + nSeam->Z() ));
3232               gp_XY uv;
3233               getClosestUV( projector, pMid, uv );
3234               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3235                 nodesNearSeam.insert( n );
3236                 nbUseMap2++;
3237               }
3238               else
3239                 nbUseMap1++;
3240             }
3241             // for centroidalSmooth all element nodes must
3242             // be on one side of a seam
3243             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3244               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3245               nn = 0;
3246               while ( nn++ < nbn ) {
3247                 const SMDS_MeshNode* n =
3248                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3249                 setMovableNodes.erase( n );
3250               }
3251             }
3252           }
3253         } // loop on nodes on seam
3254       } // loop on edge of a face
3255     } // if ( !face.IsNull() )
3256
3257     if ( setMovableNodes.empty() ) {
3258       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3259       continue; // goto next face
3260     }
3261
3262     // -------------
3263     // SMOOTHING //
3264     // -------------
3265
3266     int it = -1;
3267     double maxRatio = -1., maxDisplacement = -1.;
3268     set<const SMDS_MeshNode*>::iterator nodeToMove;
3269     for ( it = 0; it < theNbIterations; it++ ) {
3270       maxDisplacement = 0.;
3271       nodeToMove = setMovableNodes.begin();
3272       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3273         const SMDS_MeshNode* node = (*nodeToMove);
3274         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3275
3276         // smooth
3277         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3278         if ( theSmoothMethod == LAPLACIAN )
3279           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3280         else
3281           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3282
3283         // node displacement
3284         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3285         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3286         if ( aDispl > maxDisplacement )
3287           maxDisplacement = aDispl;
3288       }
3289       // no node movement => exit
3290       //if ( maxDisplacement < 1.e-16 ) {
3291       if ( maxDisplacement < disttol ) {
3292         MESSAGE("-- no node movement --");
3293         break;
3294       }
3295
3296       // check elements quality
3297       maxRatio  = 0;
3298       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3299       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3300         const SMDS_MeshElement* elem = (*elemIt);
3301         if ( !elem || elem->GetType() != SMDSAbs_Face )
3302           continue;
3303         SMESH::Controls::TSequenceOfXYZ aPoints;
3304         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3305           double aValue = aQualityFunc.GetValue( aPoints );
3306           if ( aValue > maxRatio )
3307             maxRatio = aValue;
3308         }
3309       }
3310       if ( maxRatio <= theTgtAspectRatio ) {
3311         MESSAGE("-- quality achived --");
3312         break;
3313       }
3314       if (it+1 == theNbIterations) {
3315         MESSAGE("-- Iteration limit exceeded --");
3316       }
3317     } // smoothing iterations
3318
3319     MESSAGE(" Face id: " << *fId <<
3320             " Nb iterstions: " << it <<
3321             " Displacement: " << maxDisplacement <<
3322             " Aspect Ratio " << maxRatio);
3323
3324     // ---------------------------------------
3325     // new nodes positions are computed,
3326     // record movement in DS and set new UV
3327     // ---------------------------------------
3328     nodeToMove = setMovableNodes.begin();
3329     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3330       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3331       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3332       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3333       if ( node_uv != uvMap.end() ) {
3334         gp_XY* uv = node_uv->second;
3335         node->SetPosition
3336           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3337       }
3338     }
3339
3340     // move medium nodes of quadratic elements
3341     if ( isQuadratic )
3342     {
3343       SMESH_MesherHelper helper( *GetMesh() );
3344       if ( !face.IsNull() )
3345         helper.SetSubShape( face );
3346       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3347       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3348         const SMDS_VtkFace* QF =
3349           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3350         if(QF && QF->IsQuadratic()) {
3351           vector<const SMDS_MeshNode*> Ns;
3352           Ns.reserve(QF->NbNodes()+1);
3353           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3354           while ( anIter->more() )
3355             Ns.push_back( cast2Node(anIter->next()) );
3356           Ns.push_back( Ns[0] );
3357           double x, y, z;
3358           for(int i=0; i<QF->NbNodes(); i=i+2) {
3359             if ( !surface.IsNull() ) {
3360               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3361               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3362               gp_XY uv = ( uv1 + uv2 ) / 2.;
3363               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3364               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3365             }
3366             else {
3367               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3368               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3369               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3370             }
3371             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3372                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3373                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3374               // we have to move i+1 node
3375               aMesh->MoveNode( Ns[i+1], x, y, z );
3376             }
3377           }
3378         }
3379       }
3380     }
3381
3382   } // loop on face ids
3383
3384 }
3385
3386 //=======================================================================
3387 //function : isReverse
3388 //purpose  : Return true if normal of prevNodes is not co-directied with
3389 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3390 //           iNotSame is where prevNodes and nextNodes are different
3391 //=======================================================================
3392
3393 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3394                       vector<const SMDS_MeshNode*> nextNodes,
3395                       const int            nbNodes,
3396                       const int            iNotSame)
3397 {
3398   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3399   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3400
3401   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3402   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3403   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3404   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3405
3406   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3407   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3408   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3409   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3410
3411   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3412
3413   return (vA ^ vB) * vN < 0.0;
3414 }
3415
3416 //=======================================================================
3417 /*!
3418  * \brief Create elements by sweeping an element
3419  * \param elem - element to sweep
3420  * \param newNodesItVec - nodes generated from each node of the element
3421  * \param newElems - generated elements
3422  * \param nbSteps - number of sweeping steps
3423  * \param srcElements - to append elem for each generated element
3424  */
3425 //=======================================================================
3426
3427 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3428                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3429                                     list<const SMDS_MeshElement*>&        newElems,
3430                                     const int                             nbSteps,
3431                                     SMESH_SequenceOfElemPtr&              srcElements)
3432 {
3433   //MESSAGE("sweepElement " << nbSteps);
3434   SMESHDS_Mesh* aMesh = GetMeshDS();
3435
3436   // Loop on elem nodes:
3437   // find new nodes and detect same nodes indices
3438   int nbNodes = elem->NbNodes();
3439   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3440   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3441   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3442   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3443
3444   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3445   vector<int> sames(nbNodes);
3446   vector<bool> issimple(nbNodes);
3447
3448   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3449     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3450     const SMDS_MeshNode*                 node         = nnIt->first;
3451     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3452     if ( listNewNodes.empty() ) {
3453       return;
3454     }
3455
3456     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3457
3458     itNN[ iNode ] = listNewNodes.begin();
3459     prevNod[ iNode ] = node;
3460     nextNod[ iNode ] = listNewNodes.front();
3461     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3462       if ( prevNod[ iNode ] != nextNod [ iNode ])
3463         iNotSameNode = iNode;
3464       else {
3465         iSameNode = iNode;
3466         //nbSame++;
3467         sames[nbSame++] = iNode;
3468       }
3469     }
3470   }
3471
3472   //cerr<<"  nbSame = "<<nbSame<<endl;
3473   if ( nbSame == nbNodes || nbSame > 2) {
3474     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3475     //INFOS( " Too many same nodes of element " << elem->GetID() );
3476     return;
3477   }
3478
3479   //  if( elem->IsQuadratic() && nbSame>0 ) {
3480   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3481   //    return;
3482   //  }
3483
3484   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3485   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3486   if ( nbSame > 0 ) {
3487     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3488     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3489     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3490   }
3491
3492   //if(nbNodes==8)
3493   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3494   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3495   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3496   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3497
3498   // check element orientation
3499   int i0 = 0, i2 = 2;
3500   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3501     //MESSAGE("Reversed elem " << elem );
3502     i0 = 2;
3503     i2 = 0;
3504     if ( nbSame > 0 )
3505       std::swap( iBeforeSame, iAfterSame );
3506   }
3507
3508   // make new elements
3509   const SMDS_MeshElement* lastElem = elem;
3510   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3511     // get next nodes
3512     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3513       if(issimple[iNode]) {
3514         nextNod[ iNode ] = *itNN[ iNode ];
3515         itNN[ iNode ]++;
3516       }
3517       else {
3518         if( elem->GetType()==SMDSAbs_Node ) {
3519           // we have to use two nodes
3520           midlNod[ iNode ] = *itNN[ iNode ];
3521           itNN[ iNode ]++;
3522           nextNod[ iNode ] = *itNN[ iNode ];
3523           itNN[ iNode ]++;
3524         }
3525         else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3526           // we have to use each second node
3527           //itNN[ iNode ]++;
3528           nextNod[ iNode ] = *itNN[ iNode ];
3529           itNN[ iNode ]++;
3530         }
3531         else {
3532           // we have to use two nodes
3533           midlNod[ iNode ] = *itNN[ iNode ];
3534           itNN[ iNode ]++;
3535           nextNod[ iNode ] = *itNN[ iNode ];
3536           itNN[ iNode ]++;
3537         }
3538       }
3539     }
3540     SMDS_MeshElement* aNewElem = 0;
3541     if(!elem->IsPoly()) {
3542       switch ( nbNodes ) {
3543       case 0:
3544         return;
3545       case 1: { // NODE
3546         if ( nbSame == 0 ) {
3547           if(issimple[0])
3548             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3549           else
3550             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3551         }
3552         break;
3553       }
3554       case 2: { // EDGE
3555         if ( nbSame == 0 )
3556           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3557                                     nextNod[ 1 ], nextNod[ 0 ] );
3558         else
3559           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3560                                     nextNod[ iNotSameNode ] );
3561         break;
3562       }
3563
3564       case 3: { // TRIANGLE or quadratic edge
3565         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3566
3567           if ( nbSame == 0 )       // --- pentahedron
3568             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3569                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3570
3571           else if ( nbSame == 1 )  // --- pyramid
3572             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3573                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3574                                          nextNod[ iSameNode ]);
3575
3576           else // 2 same nodes:      --- tetrahedron
3577             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3578                                          nextNod[ iNotSameNode ]);
3579         }
3580         else { // quadratic edge
3581           if(nbSame==0) {     // quadratic quadrangle
3582             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3583                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3584           }
3585           else if(nbSame==1) { // quadratic triangle
3586             if(sames[0]==2) {
3587               return; // medium node on axis
3588             }
3589             else if(sames[0]==0) {
3590               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3591                                         nextNod[2], midlNod[1], prevNod[2]);
3592             }
3593             else { // sames[0]==1
3594               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3595                                         midlNod[0], nextNod[2], prevNod[2]);
3596             }
3597           }
3598           else {
3599             return;
3600           }
3601         }
3602         break;
3603       }
3604       case 4: { // QUADRANGLE
3605
3606         if ( nbSame == 0 )       // --- hexahedron
3607           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3608                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3609
3610         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3611           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3612                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3613                                        nextNod[ iSameNode ]);
3614           newElems.push_back( aNewElem );
3615           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3616                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3617                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3618         }
3619         else if ( nbSame == 2 ) { // pentahedron
3620           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3621             // iBeforeSame is same too
3622             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3623                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3624                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3625           else
3626             // iAfterSame is same too
3627             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3628                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3629                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3630         }
3631         break;
3632       }
3633       case 6: { // quadratic triangle
3634         // create pentahedron with 15 nodes
3635         if(nbSame==0) {
3636           if(i0>0) { // reversed case
3637             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3638                                          nextNod[0], nextNod[2], nextNod[1],
3639                                          prevNod[5], prevNod[4], prevNod[3],
3640                                          nextNod[5], nextNod[4], nextNod[3],
3641                                          midlNod[0], midlNod[2], midlNod[1]);
3642           }
3643           else { // not reversed case
3644             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3645                                          nextNod[0], nextNod[1], nextNod[2],
3646                                          prevNod[3], prevNod[4], prevNod[5],
3647                                          nextNod[3], nextNod[4], nextNod[5],
3648                                          midlNod[0], midlNod[1], midlNod[2]);
3649           }
3650         }
3651         else if(nbSame==1) {
3652           // 2d order pyramid of 13 nodes
3653           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3654           //                                 int n12,int n23,int n34,int n41,
3655           //                                 int n15,int n25,int n35,int n45, int ID);
3656           int n5 = iSameNode;
3657           int n1,n4,n41,n15,n45;
3658           if(i0>0) { // reversed case
3659             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3660             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3661             n41 = n1 + 3;
3662             n15 = n5 + 3;
3663             n45 = n4 + 3;
3664           }
3665           else {
3666             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3667             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3668             n41 = n4 + 3;
3669             n15 = n1 + 3;
3670             n45 = n5 + 3;
3671           }
3672           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3673                                       nextNod[n4], prevNod[n4], prevNod[n5],
3674                                       midlNod[n1], nextNod[n41],
3675                                       midlNod[n4], prevNod[n41],
3676                                       prevNod[n15], nextNod[n15],
3677                                       nextNod[n45], prevNod[n45]);
3678         }
3679         else if(nbSame==2) {
3680           // 2d order tetrahedron of 10 nodes
3681           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3682           //                                 int n12,int n23,int n31,
3683           //                                 int n14,int n24,int n34, int ID);
3684           int n1 = iNotSameNode;
3685           int n2,n3,n12,n23,n31;
3686           if(i0>0) { // reversed case
3687             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3688             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3689             n12 = n2 + 3;
3690             n23 = n3 + 3;
3691             n31 = n1 + 3;
3692           }
3693           else {
3694             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3695             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3696             n12 = n1 + 3;
3697             n23 = n2 + 3;
3698             n31 = n3 + 3;
3699           }
3700           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3701                                        prevNod[n12], prevNod[n23], prevNod[n31],
3702                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3703         }
3704         break;
3705       }
3706       case 8: { // quadratic quadrangle
3707         if(nbSame==0) {
3708           // create hexahedron with 20 nodes
3709           if(i0>0) { // reversed case
3710             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3711                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3712                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3713                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3714                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3715           }
3716           else { // not reversed case
3717             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3718                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3719                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3720                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3721                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3722           }
3723         }
3724         else if(nbSame==1) { 
3725           // --- pyramid + pentahedron - can not be created since it is needed 
3726           // additional middle node ot the center of face
3727           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3728           return;
3729         }
3730         else if(nbSame==2) {
3731           // 2d order Pentahedron with 15 nodes
3732           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3733           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3734           //                                 int n14,int n25,int n36, int ID);
3735           int n1,n2,n4,n5;
3736           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3737             // iBeforeSame is same too
3738             n1 = iBeforeSame;
3739             n2 = iOpposSame;
3740             n4 = iSameNode;
3741             n5 = iAfterSame;
3742           }
3743           else {
3744             // iAfterSame is same too
3745             n1 = iSameNode;
3746             n2 = iBeforeSame;
3747             n4 = iAfterSame;
3748             n5 = iOpposSame;
3749           }
3750           int n12,n45,n14,n25;
3751           if(i0>0) { //reversed case
3752             n12 = n1 + 4;
3753             n45 = n5 + 4;
3754             n14 = n4 + 4;
3755             n25 = n2 + 4;
3756           }
3757           else {
3758             n12 = n2 + 4;
3759             n45 = n4 + 4;
3760             n14 = n1 + 4;
3761             n25 = n5 + 4;
3762           }
3763           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3764                                        prevNod[n4], prevNod[n5], nextNod[n5],
3765                                        prevNod[n12], midlNod[n2], nextNod[n12],
3766                                        prevNod[n45], midlNod[n5], nextNod[n45],
3767                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3768         }
3769         break;
3770       }
3771       default: {
3772         // realized for extrusion only
3773         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3774         //vector<int> quantities (nbNodes + 2);
3775
3776         //quantities[0] = nbNodes; // bottom of prism
3777         //for (int inode = 0; inode < nbNodes; inode++) {
3778         //  polyedre_nodes[inode] = prevNod[inode];
3779         //}
3780
3781         //quantities[1] = nbNodes; // top of prism
3782         //for (int inode = 0; inode < nbNodes; inode++) {
3783         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3784         //}
3785
3786         //for (int iface = 0; iface < nbNodes; iface++) {
3787         //  quantities[iface + 2] = 4;
3788         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3789         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3790         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3791         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3792         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3793         //}
3794         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3795         break;
3796       }
3797       }
3798     }
3799
3800     if(!aNewElem) {
3801       // realized for extrusion only
3802       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3803       vector<int> quantities (nbNodes + 2);
3804
3805       quantities[0] = nbNodes; // bottom of prism
3806       for (int inode = 0; inode < nbNodes; inode++) {
3807         polyedre_nodes[inode] = prevNod[inode];
3808       }
3809
3810       quantities[1] = nbNodes; // top of prism
3811       for (int inode = 0; inode < nbNodes; inode++) {
3812         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3813       }
3814
3815       for (int iface = 0; iface < nbNodes; iface++) {
3816         quantities[iface + 2] = 4;
3817         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3818         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3819         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3820         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3821         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3822       }
3823       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3824     }
3825
3826     if ( aNewElem ) {
3827       newElems.push_back( aNewElem );
3828       myLastCreatedElems.Append(aNewElem);
3829       srcElements.Append( elem );
3830       lastElem = aNewElem;
3831     }
3832
3833     // set new prev nodes
3834     for ( iNode = 0; iNode < nbNodes; iNode++ )
3835       prevNod[ iNode ] = nextNod[ iNode ];
3836
3837   } // for steps
3838 }
3839
3840 //=======================================================================
3841 /*!
3842  * \brief Create 1D and 2D elements around swept elements
3843  * \param mapNewNodes - source nodes and ones generated from them
3844  * \param newElemsMap - source elements and ones generated from them
3845  * \param elemNewNodesMap - nodes generated from each node of each element
3846  * \param elemSet - all swept elements
3847  * \param nbSteps - number of sweeping steps
3848  * \param srcElements - to append elem for each generated element
3849  */
3850 //=======================================================================
3851
3852 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3853                                   TElemOfElemListMap &     newElemsMap,
3854                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3855                                   TIDSortedElemSet&        elemSet,
3856                                   const int                nbSteps,
3857                                   SMESH_SequenceOfElemPtr& srcElements)
3858 {
3859   MESSAGE("makeWalls");
3860   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3861   SMESHDS_Mesh* aMesh = GetMeshDS();
3862
3863   // Find nodes belonging to only one initial element - sweep them to get edges.
3864
3865   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3866   for ( ; nList != mapNewNodes.end(); nList++ ) {
3867     const SMDS_MeshNode* node =
3868       static_cast<const SMDS_MeshNode*>( nList->first );
3869     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3870     int nbInitElems = 0;
3871     const SMDS_MeshElement* el = 0;
3872     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3873     while ( eIt->more() && nbInitElems < 2 ) {
3874       el = eIt->next();
3875       SMDSAbs_ElementType type = el->GetType();
3876       if ( type == SMDSAbs_Volume || type < highType ) continue;
3877       if ( type > highType ) {
3878         nbInitElems = 0;
3879         highType = type;
3880       }
3881       if ( elemSet.find(el) != elemSet.end() )
3882         nbInitElems++;
3883     }
3884     if ( nbInitElems < 2 ) {
3885       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3886       if(!NotCreateEdge) {
3887         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3888         list<const SMDS_MeshElement*> newEdges;
3889         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3890       }
3891     }
3892   }
3893
3894   // Make a ceiling for each element ie an equal element of last new nodes.
3895   // Find free links of faces - make edges and sweep them into faces.
3896
3897   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3898   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3899   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3900     const SMDS_MeshElement* elem = itElem->first;
3901     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3902
3903     if(itElem->second.size()==0) continue;
3904
3905     if ( elem->GetType() == SMDSAbs_Edge ) {
3906       // create a ceiling edge
3907       if (!elem->IsQuadratic()) {
3908         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3909                                vecNewNodes[ 1 ]->second.back())) {
3910           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3911                                                    vecNewNodes[ 1 ]->second.back()));
3912           srcElements.Append( myLastCreatedElems.Last() );
3913         }
3914       }
3915       else {
3916         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3917                                vecNewNodes[ 1 ]->second.back(),
3918                                vecNewNodes[ 2 ]->second.back())) {
3919           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3920                                                    vecNewNodes[ 1 ]->second.back(),
3921                                                    vecNewNodes[ 2 ]->second.back()));
3922           srcElements.Append( myLastCreatedElems.Last() );
3923         }
3924       }
3925     }
3926     if ( elem->GetType() != SMDSAbs_Face )
3927       continue;
3928
3929     bool hasFreeLinks = false;
3930
3931     TIDSortedElemSet avoidSet;
3932     avoidSet.insert( elem );
3933
3934     set<const SMDS_MeshNode*> aFaceLastNodes;
3935     int iNode, nbNodes = vecNewNodes.size();
3936     if(!elem->IsQuadratic()) {
3937       // loop on the face nodes
3938       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3939         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3940         // look for free links of the face
3941         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3942         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3943         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3944         // check if a link is free
3945         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3946           hasFreeLinks = true;
3947           // make an edge and a ceiling for a new edge
3948           if ( !aMesh->FindEdge( n1, n2 )) {
3949             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3950             srcElements.Append( myLastCreatedElems.Last() );
3951           }
3952           n1 = vecNewNodes[ iNode ]->second.back();
3953           n2 = vecNewNodes[ iNext ]->second.back();
3954           if ( !aMesh->FindEdge( n1, n2 )) {
3955             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3956             srcElements.Append( myLastCreatedElems.Last() );
3957           }
3958         }
3959       }
3960     }
3961     else { // elem is quadratic face
3962       int nbn = nbNodes/2;
3963       for ( iNode = 0; iNode < nbn; iNode++ ) {
3964         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3965         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3966         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3967         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3968         // check if a link is free
3969         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3970           hasFreeLinks = true;
3971           // make an edge and a ceiling for a new edge
3972           // find medium node
3973           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3974           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3975             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3976             srcElements.Append( myLastCreatedElems.Last() );
3977           }
3978           n1 = vecNewNodes[ iNode ]->second.back();
3979           n2 = vecNewNodes[ iNext ]->second.back();
3980           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3981           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3982             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3983             srcElements.Append( myLastCreatedElems.Last() );
3984           }
3985         }
3986       }
3987       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3988         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3989       }
3990     }
3991
3992     // sweep free links into faces
3993
3994     if ( hasFreeLinks )  {
3995       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3996       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3997
3998       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3999       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4000         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4001         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4002       }
4003       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4004         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4005         iVol = 0;
4006         while ( iVol++ < volNb ) v++;
4007         // find indices of free faces of a volume and their source edges
4008         list< int > freeInd;
4009         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4010         SMDS_VolumeTool vTool( *v );
4011         int iF, nbF = vTool.NbFaces();
4012         for ( iF = 0; iF < nbF; iF ++ ) {
4013           if (vTool.IsFreeFace( iF ) &&
4014               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4015               initNodeSet != faceNodeSet) // except an initial face
4016           {
4017             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4018               continue;
4019             freeInd.push_back( iF );
4020             // find source edge of a free face iF
4021             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4022             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4023             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4024                                    initNodeSet.begin(), initNodeSet.end(),
4025                                    commonNodes.begin());
4026             if ( (*v)->IsQuadratic() )
4027               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4028             else
4029               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4030 #ifdef _DEBUG_
4031             if ( !srcEdges.back() )
4032             {
4033               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4034                    << iF << " of volume #" << vTool.ID() << endl;
4035             }
4036 #endif
4037           }
4038         }
4039         if ( freeInd.empty() )
4040           continue;
4041
4042         // create faces for all steps;
4043         // if such a face has been already created by sweep of edge,
4044         // assure that its orientation is OK
4045         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
4046           vTool.Set( *v );
4047           vTool.SetExternalNormal();
4048           list< int >::iterator ind = freeInd.begin();
4049           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4050           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4051           {
4052             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4053             int nbn = vTool.NbFaceNodes( *ind );
4054             switch ( nbn ) {
4055             case 3: { ///// triangle
4056               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4057               if ( !f )
4058                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4059               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4060                 {
4061                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4062                   aMesh->RemoveElement(f);
4063                 }
4064               break;
4065             }
4066             case 4: { ///// quadrangle
4067               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4068               if ( !f )
4069                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4070               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4071                 {
4072                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4073                   aMesh->RemoveElement(f);
4074                 }
4075               break;
4076             }
4077             default:
4078               if( (*v)->IsQuadratic() ) {
4079                 if(nbn==6) { /////// quadratic triangle
4080                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4081                                                              nodes[1], nodes[3], nodes[5] );
4082                   if ( !f ) {
4083                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4084                                                              nodes[1], nodes[3], nodes[5]));
4085                   }
4086                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4087                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4088                     tmpnodes[0] = nodes[0];
4089                     tmpnodes[1] = nodes[2];
4090                     tmpnodes[2] = nodes[4];
4091                     tmpnodes[3] = nodes[1];
4092                     tmpnodes[4] = nodes[3];
4093                     tmpnodes[5] = nodes[5];
4094                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4095                                                              nodes[1], nodes[3], nodes[5]));
4096                     aMesh->RemoveElement(f);
4097                   }
4098                 }
4099                 else {       /////// quadratic quadrangle
4100                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4101                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
4102                   if ( !f ) {
4103                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4104                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4105                   }
4106                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4107                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4108                     tmpnodes[0] = nodes[0];
4109                     tmpnodes[1] = nodes[2];
4110                     tmpnodes[2] = nodes[4];
4111                     tmpnodes[3] = nodes[6];
4112                     tmpnodes[4] = nodes[1];
4113                     tmpnodes[5] = nodes[3];
4114                     tmpnodes[6] = nodes[5];
4115                     tmpnodes[7] = nodes[7];
4116                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4117                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4118                     aMesh->RemoveElement(f);
4119                   }
4120                 }
4121               }
4122               else { //////// polygon
4123                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4124                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4125                 if ( !f )
4126                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4127                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4128                   {
4129                   // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4130                   MESSAGE("ChangeElementNodes");
4131                   aMesh->ChangeElementNodes( f, nodes, nbn );
4132                   }
4133               }
4134             }
4135             while ( srcElements.Length() < myLastCreatedElems.Length() )
4136               srcElements.Append( *srcEdge );
4137
4138           }  // loop on free faces
4139
4140           // go to the next volume
4141           iVol = 0;
4142           while ( iVol++ < nbVolumesByStep ) v++;
4143         }
4144       }
4145     } // sweep free links into faces
4146
4147     // Make a ceiling face with a normal external to a volume
4148
4149     SMDS_VolumeTool lastVol( itElem->second.back() );
4150
4151     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4152     if ( iF >= 0 ) {
4153       lastVol.SetExternalNormal();
4154       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4155       int nbn = lastVol.NbFaceNodes( iF );
4156       switch ( nbn ) {
4157       case 3:
4158         if (!hasFreeLinks ||
4159             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4160           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4161         break;
4162       case 4:
4163         if (!hasFreeLinks ||
4164             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4165           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4166         break;
4167       default:
4168         if(itElem->second.back()->IsQuadratic()) {
4169           if(nbn==6) {
4170             if (!hasFreeLinks ||
4171                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4172                                  nodes[1], nodes[3], nodes[5]) ) {
4173               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4174                                                        nodes[1], nodes[3], nodes[5]));
4175             }
4176           }
4177           else { // nbn==8
4178             if (!hasFreeLinks ||
4179                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4180                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4181               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4182                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4183           }
4184         }
4185         else {
4186           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4187           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4188             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4189         }
4190       } // switch
4191
4192       while ( srcElements.Length() < myLastCreatedElems.Length() )
4193         srcElements.Append( myLastCreatedElems.Last() );
4194     }
4195   } // loop on swept elements
4196 }
4197
4198 //=======================================================================
4199 //function : RotationSweep
4200 //purpose  :
4201 //=======================================================================
4202
4203 SMESH_MeshEditor::PGroupIDs
4204 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4205                                 const gp_Ax1&      theAxis,
4206                                 const double       theAngle,
4207                                 const int          theNbSteps,
4208                                 const double       theTol,
4209                                 const bool         theMakeGroups,
4210                                 const bool         theMakeWalls)
4211 {
4212   myLastCreatedElems.Clear();
4213   myLastCreatedNodes.Clear();
4214
4215   // source elements for each generated one
4216   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4217
4218   MESSAGE( "RotationSweep()");
4219   gp_Trsf aTrsf;
4220   aTrsf.SetRotation( theAxis, theAngle );
4221   gp_Trsf aTrsf2;
4222   aTrsf2.SetRotation( theAxis, theAngle/2. );
4223
4224   gp_Lin aLine( theAxis );
4225   double aSqTol = theTol * theTol;
4226
4227   SMESHDS_Mesh* aMesh = GetMeshDS();
4228
4229   TNodeOfNodeListMap mapNewNodes;
4230   TElemOfVecOfNnlmiMap mapElemNewNodes;
4231   TElemOfElemListMap newElemsMap;
4232
4233   // loop on theElems
4234   TIDSortedElemSet::iterator itElem;
4235   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4236     const SMDS_MeshElement* elem = *itElem;
4237     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4238       continue;
4239     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4240     newNodesItVec.reserve( elem->NbNodes() );
4241
4242     // loop on elem nodes
4243     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4244     while ( itN->more() ) {
4245       // check if a node has been already sweeped
4246       const SMDS_MeshNode* node = cast2Node( itN->next() );
4247
4248       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4249       double coord[3];
4250       aXYZ.Coord( coord[0], coord[1], coord[2] );
4251       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4252
4253       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4254       if ( nIt == mapNewNodes.end() ) {
4255         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4256         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4257
4258         // make new nodes
4259         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4260         //double coord[3];
4261         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4262         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4263         const SMDS_MeshNode * newNode = node;
4264         for ( int i = 0; i < theNbSteps; i++ ) {
4265           if ( !isOnAxis ) {
4266             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4267               // create two nodes
4268               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4269               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4270               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4271               myLastCreatedNodes.Append(newNode);
4272               srcNodes.Append( node );
4273               listNewNodes.push_back( newNode );
4274               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4275               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4276             }
4277             else {
4278               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4279             }
4280             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4281             myLastCreatedNodes.Append(newNode);
4282             srcNodes.Append( node );
4283             listNewNodes.push_back( newNode );
4284           }
4285           else {
4286             listNewNodes.push_back( newNode );
4287             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4288               listNewNodes.push_back( newNode );
4289             }
4290           }
4291         }
4292       }
4293       /*
4294         else {
4295         // if current elem is quadratic and current node is not medium
4296         // we have to check - may be it is needed to insert additional nodes
4297         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4298         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4299         if(listNewNodes.size()==theNbSteps) {
4300         listNewNodes.clear();
4301         // make new nodes
4302         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4303         //double coord[3];
4304         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4305         const SMDS_MeshNode * newNode = node;
4306         if ( !isOnAxis ) {
4307         for(int i = 0; i<theNbSteps; i++) {
4308         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4309         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4310         cout<<"    3 AddNode:  "<<newNode;
4311         myLastCreatedNodes.Append(newNode);
4312         listNewNodes.push_back( newNode );
4313         srcNodes.Append( node );
4314         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4315         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4316         cout<<"    4 AddNode:  "<<newNode;
4317         myLastCreatedNodes.Append(newNode);
4318         srcNodes.Append( node );
4319         listNewNodes.push_back( newNode );
4320         }
4321         }
4322         else {
4323         listNewNodes.push_back( newNode );
4324         }
4325         }
4326         }
4327         }
4328       */
4329       newNodesItVec.push_back( nIt );
4330     }
4331     // make new elements
4332     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4333   }
4334
4335   if ( theMakeWalls )
4336     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4337
4338   PGroupIDs newGroupIDs;
4339   if ( theMakeGroups )
4340     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4341
4342   return newGroupIDs;
4343 }
4344
4345
4346 //=======================================================================
4347 //function : CreateNode
4348 //purpose  :
4349 //=======================================================================
4350 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4351                                                   const double y,
4352                                                   const double z,
4353                                                   const double tolnode,
4354                                                   SMESH_SequenceOfNode& aNodes)
4355 {
4356   myLastCreatedElems.Clear();
4357   myLastCreatedNodes.Clear();
4358
4359   gp_Pnt P1(x,y,z);
4360   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4361
4362   // try to search in sequence of existing nodes
4363   // if aNodes.Length()>0 we 'nave to use given sequence
4364   // else - use all nodes of mesh
4365   if(aNodes.Length()>0) {
4366     int i;
4367     for(i=1; i<=aNodes.Length(); i++) {
4368       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4369       if(P1.Distance(P2)<tolnode)
4370         return aNodes.Value(i);
4371     }
4372   }
4373   else {
4374     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4375     while(itn->more()) {
4376       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4377       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4378       if(P1.Distance(P2)<tolnode)
4379         return aN;
4380     }
4381   }
4382
4383   // create new node and return it
4384   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4385   myLastCreatedNodes.Append(NewNode);
4386   return NewNode;
4387 }
4388
4389
4390 //=======================================================================
4391 //function : ExtrusionSweep
4392 //purpose  :
4393 //=======================================================================
4394
4395 SMESH_MeshEditor::PGroupIDs
4396 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4397                                   const gp_Vec&       theStep,
4398                                   const int           theNbSteps,
4399                                   TElemOfElemListMap& newElemsMap,
4400                                   const bool          theMakeGroups,
4401                                   const int           theFlags,
4402                                   const double        theTolerance)
4403 {
4404   ExtrusParam aParams;
4405   aParams.myDir = gp_Dir(theStep);
4406   aParams.myNodes.Clear();
4407   aParams.mySteps = new TColStd_HSequenceOfReal;
4408   int i;
4409   for(i=1; i<=theNbSteps; i++)
4410     aParams.mySteps->Append(theStep.Magnitude());
4411
4412   return
4413     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4414 }
4415
4416
4417 //=======================================================================
4418 //function : ExtrusionSweep
4419 //purpose  :
4420 //=======================================================================
4421
4422 SMESH_MeshEditor::PGroupIDs
4423 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4424                                   ExtrusParam&        theParams,
4425                                   TElemOfElemListMap& newElemsMap,
4426                                   const bool          theMakeGroups,
4427                                   const int           theFlags,
4428                                   const double        theTolerance)
4429 {
4430   MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4431   myLastCreatedElems.Clear();
4432   myLastCreatedNodes.Clear();
4433
4434   // source elements for each generated one
4435   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4436
4437   SMESHDS_Mesh* aMesh = GetMeshDS();
4438
4439   int nbsteps = theParams.mySteps->Length();
4440
4441   TNodeOfNodeListMap mapNewNodes;
4442   //TNodeOfNodeVecMap mapNewNodes;
4443   TElemOfVecOfNnlmiMap mapElemNewNodes;
4444   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4445
4446   // loop on theElems
4447   TIDSortedElemSet::iterator itElem;
4448   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4449     // check element type
4450     const SMDS_MeshElement* elem = *itElem;
4451     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4452       continue;
4453
4454     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4455     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4456     newNodesItVec.reserve( elem->NbNodes() );
4457
4458     // loop on elem nodes
4459     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4460     while ( itN->more() )
4461     {
4462       // check if a node has been already sweeped
4463       const SMDS_MeshNode* node = cast2Node( itN->next() );
4464       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4465       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4466       if ( nIt == mapNewNodes.end() ) {
4467         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4468         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4469         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4470         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4471         //vecNewNodes.reserve(nbsteps);
4472
4473         // make new nodes
4474         double coord[] = { node->X(), node->Y(), node->Z() };
4475         //int nbsteps = theParams.mySteps->Length();
4476         for ( int i = 0; i < nbsteps; i++ ) {
4477           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4478             // create additional node
4479             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4480             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4481             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4482             if( theFlags & EXTRUSION_FLAG_SEW ) {
4483               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4484                                                          theTolerance, theParams.myNodes);
4485               listNewNodes.push_back( newNode );
4486             }
4487             else {
4488               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4489               myLastCreatedNodes.Append(newNode);
4490               srcNodes.Append( node );
4491               listNewNodes.push_back( newNode );
4492             }
4493           }
4494           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4495           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4496           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4497           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4498           if( theFlags & EXTRUSION_FLAG_SEW ) {
4499             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4500                                                        theTolerance, theParams.myNodes);
4501             listNewNodes.push_back( newNode );
4502             //vecNewNodes[i]=newNode;
4503           }
4504           else {
4505             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4506             myLastCreatedNodes.Append(newNode);
4507             srcNodes.Append( node );
4508             listNewNodes.push_back( newNode );
4509             //vecNewNodes[i]=newNode;
4510           }
4511         }
4512       }
4513       else {
4514         // if current elem is quadratic and current node is not medium
4515         // we have to check - may be it is needed to insert additional nodes
4516         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4517           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4518           if(listNewNodes.size()==nbsteps) {
4519             listNewNodes.clear();
4520             double coord[] = { node->X(), node->Y(), node->Z() };
4521             for ( int i = 0; i < nbsteps; i++ ) {
4522               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4523               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4524               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4525               if( theFlags & EXTRUSION_FLAG_SEW ) {
4526                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4527                                                            theTolerance, theParams.myNodes);
4528                 listNewNodes.push_back( newNode );
4529               }
4530               else {
4531                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4532                 myLastCreatedNodes.Append(newNode);
4533                 srcNodes.Append( node );
4534                 listNewNodes.push_back( newNode );
4535               }
4536               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4537               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4538               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4539               if( theFlags & EXTRUSION_FLAG_SEW ) {
4540                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4541                                                            theTolerance, theParams.myNodes);
4542                 listNewNodes.push_back( newNode );
4543               }
4544               else {
4545                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4546                 myLastCreatedNodes.Append(newNode);
4547                 srcNodes.Append( node );
4548                 listNewNodes.push_back( newNode );
4549               }
4550             }
4551           }
4552         }
4553       }
4554       newNodesItVec.push_back( nIt );
4555     }
4556     // make new elements
4557     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4558   }
4559
4560   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4561     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4562   }
4563   PGroupIDs newGroupIDs;
4564   if ( theMakeGroups )
4565     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4566
4567   return newGroupIDs;
4568 }
4569
4570 /*
4571 //=======================================================================
4572 //class    : SMESH_MeshEditor_PathPoint
4573 //purpose  : auxiliary class
4574 //=======================================================================
4575 class SMESH_MeshEditor_PathPoint {
4576 public:
4577 SMESH_MeshEditor_PathPoint() {
4578 myPnt.SetCoord(99., 99., 99.);
4579 myTgt.SetCoord(1.,0.,0.);
4580 myAngle=0.;
4581 myPrm=0.;
4582 }
4583 void SetPnt(const gp_Pnt& aP3D){
4584 myPnt=aP3D;
4585 }
4586 void SetTangent(const gp_Dir& aTgt){
4587 myTgt=aTgt;
4588 }
4589 void SetAngle(const double& aBeta){
4590 myAngle=aBeta;
4591 }
4592 void SetParameter(const double& aPrm){
4593 myPrm=aPrm;
4594 }
4595 const gp_Pnt& Pnt()const{
4596 return myPnt;
4597 }
4598 const gp_Dir& Tangent()const{
4599 return myTgt;
4600 }
4601 double Angle()const{
4602 return myAngle;
4603 }
4604 double Parameter()const{
4605 return myPrm;
4606 }
4607
4608 protected:
4609 gp_Pnt myPnt;
4610 gp_Dir myTgt;
4611 double myAngle;
4612 double myPrm;
4613 };
4614 */
4615
4616 //=======================================================================
4617 //function : ExtrusionAlongTrack
4618 //purpose  :
4619 //=======================================================================
4620 SMESH_MeshEditor::Extrusion_Error
4621 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4622                                        SMESH_subMesh*       theTrack,
4623                                        const SMDS_MeshNode* theN1,
4624                                        const bool           theHasAngles,
4625                                        list<double>&        theAngles,
4626                                        const bool           theLinearVariation,
4627                                        const bool           theHasRefPoint,
4628                                        const gp_Pnt&        theRefPoint,
4629                                        const bool           theMakeGroups)
4630 {
4631   MESSAGE("ExtrusionAlongTrack");
4632   myLastCreatedElems.Clear();
4633   myLastCreatedNodes.Clear();
4634
4635   int aNbE;
4636   std::list<double> aPrms;
4637   TIDSortedElemSet::iterator itElem;
4638
4639   gp_XYZ aGC;
4640   TopoDS_Edge aTrackEdge;
4641   TopoDS_Vertex aV1, aV2;
4642
4643   SMDS_ElemIteratorPtr aItE;
4644   SMDS_NodeIteratorPtr aItN;
4645   SMDSAbs_ElementType aTypeE;
4646
4647   TNodeOfNodeListMap mapNewNodes;
4648
4649   // 1. Check data
4650   aNbE = theElements.size();
4651   // nothing to do
4652   if ( !aNbE )
4653     return EXTR_NO_ELEMENTS;
4654
4655   // 1.1 Track Pattern
4656   ASSERT( theTrack );
4657
4658   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4659
4660   aItE = pSubMeshDS->GetElements();
4661   while ( aItE->more() ) {
4662     const SMDS_MeshElement* pE = aItE->next();
4663     aTypeE = pE->GetType();
4664     // Pattern must contain links only
4665     if ( aTypeE != SMDSAbs_Edge )
4666       return EXTR_PATH_NOT_EDGE;
4667   }
4668
4669   list<SMESH_MeshEditor_PathPoint> fullList;
4670
4671   const TopoDS_Shape& aS = theTrack->GetSubShape();
4672   // Sub shape for the Pattern must be an Edge or Wire
4673   if( aS.ShapeType() == TopAbs_EDGE ) {
4674     aTrackEdge = TopoDS::Edge( aS );
4675     // the Edge must not be degenerated
4676     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4677       return EXTR_BAD_PATH_SHAPE;
4678     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4679     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4680     const SMDS_MeshNode* aN1 = aItN->next();
4681     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4682     const SMDS_MeshNode* aN2 = aItN->next();
4683     // starting node must be aN1 or aN2
4684     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4685       return EXTR_BAD_STARTING_NODE;
4686     aItN = pSubMeshDS->GetNodes();
4687     while ( aItN->more() ) {
4688       const SMDS_MeshNode* pNode = aItN->next();
4689       const SMDS_EdgePosition* pEPos =
4690         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4691       double aT = pEPos->GetUParameter();
4692       aPrms.push_back( aT );
4693     }
4694     //Extrusion_Error err =
4695     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4696   }
4697   else if( aS.ShapeType() == TopAbs_WIRE ) {
4698     list< SMESH_subMesh* > LSM;
4699     TopTools_SequenceOfShape Edges;
4700     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4701     while(itSM->more()) {
4702       SMESH_subMesh* SM = itSM->next();
4703       LSM.push_back(SM);
4704       const TopoDS_Shape& aS = SM->GetSubShape();
4705       Edges.Append(aS);
4706     }
4707     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4708     int startNid = theN1->GetID();
4709     TColStd_MapOfInteger UsedNums;
4710     int NbEdges = Edges.Length();
4711     int i = 1;
4712     for(; i<=NbEdges; i++) {
4713       int k = 0;
4714       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4715       for(; itLSM!=LSM.end(); itLSM++) {
4716         k++;
4717         if(UsedNums.Contains(k)) continue;
4718         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4719         SMESH_subMesh* locTrack = *itLSM;
4720         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4721         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4722         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4723         const SMDS_MeshNode* aN1 = aItN->next();
4724         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4725         const SMDS_MeshNode* aN2 = aItN->next();
4726         // starting node must be aN1 or aN2
4727         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4728         // 2. Collect parameters on the track edge
4729         aPrms.clear();
4730         aItN = locMeshDS->GetNodes();
4731         while ( aItN->more() ) {
4732           const SMDS_MeshNode* pNode = aItN->next();
4733           const SMDS_EdgePosition* pEPos =
4734             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4735           double aT = pEPos->GetUParameter();
4736           aPrms.push_back( aT );
4737         }
4738         list<SMESH_MeshEditor_PathPoint> LPP;
4739         //Extrusion_Error err =
4740         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4741         LLPPs.push_back(LPP);
4742         UsedNums.Add(k);
4743         // update startN for search following egde
4744         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4745         else startNid = aN1->GetID();
4746         break;
4747       }
4748     }
4749     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4750     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4751     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4752     for(; itPP!=firstList.end(); itPP++) {
4753       fullList.push_back( *itPP );
4754     }
4755     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4756     fullList.pop_back();
4757     itLLPP++;
4758     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4759       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4760       itPP = currList.begin();
4761       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4762       gp_Dir D1 = PP1.Tangent();
4763       gp_Dir D2 = PP2.Tangent();
4764       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4765                            (D1.Z()+D2.Z())/2 ) );
4766       PP1.SetTangent(Dnew);
4767       fullList.push_back(PP1);
4768       itPP++;
4769       for(; itPP!=firstList.end(); itPP++) {
4770         fullList.push_back( *itPP );
4771       }
4772       PP1 = fullList.back();
4773       fullList.pop_back();
4774     }
4775     // if wire not closed
4776     fullList.push_back(PP1);
4777     // else ???
4778   }
4779   else {
4780     return EXTR_BAD_PATH_SHAPE;
4781   }
4782
4783   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4784                           theHasRefPoint, theRefPoint, theMakeGroups);
4785 }
4786
4787
4788 //=======================================================================
4789 //function : ExtrusionAlongTrack
4790 //purpose  :
4791 //=======================================================================
4792 SMESH_MeshEditor::Extrusion_Error
4793 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4794                                        SMESH_Mesh*          theTrack,
4795                                        const SMDS_MeshNode* theN1,
4796                                        const bool           theHasAngles,
4797                                        list<double>&        theAngles,
4798                                        const bool           theLinearVariation,
4799                                        const bool           theHasRefPoint,
4800                                        const gp_Pnt&        theRefPoint,
4801                                        const bool           theMakeGroups)
4802 {
4803   myLastCreatedElems.Clear();
4804   myLastCreatedNodes.Clear();
4805
4806   int aNbE;
4807   std::list<double> aPrms;
4808   TIDSortedElemSet::iterator itElem;
4809
4810   gp_XYZ aGC;
4811   TopoDS_Edge aTrackEdge;
4812   TopoDS_Vertex aV1, aV2;
4813
4814   SMDS_ElemIteratorPtr aItE;
4815   SMDS_NodeIteratorPtr aItN;
4816   SMDSAbs_ElementType aTypeE;
4817
4818   TNodeOfNodeListMap mapNewNodes;
4819
4820   // 1. Check data
4821   aNbE = theElements.size();
4822   // nothing to do
4823   if ( !aNbE )
4824     return EXTR_NO_ELEMENTS;
4825
4826   // 1.1 Track Pattern
4827   ASSERT( theTrack );
4828
4829   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4830
4831   aItE = pMeshDS->elementsIterator();
4832   while ( aItE->more() ) {
4833     const SMDS_MeshElement* pE = aItE->next();
4834     aTypeE = pE->GetType();
4835     // Pattern must contain links only
4836     if ( aTypeE != SMDSAbs_Edge )
4837       return EXTR_PATH_NOT_EDGE;
4838   }
4839
4840   list<SMESH_MeshEditor_PathPoint> fullList;
4841
4842   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4843   // Sub shape for the Pattern must be an Edge or Wire
4844   if( aS.ShapeType() == TopAbs_EDGE ) {
4845     aTrackEdge = TopoDS::Edge( aS );
4846     // the Edge must not be degenerated
4847     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4848       return EXTR_BAD_PATH_SHAPE;
4849     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4850     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4851     const SMDS_MeshNode* aN1 = aItN->next();
4852     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4853     const SMDS_MeshNode* aN2 = aItN->next();
4854     // starting node must be aN1 or aN2
4855     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4856       return EXTR_BAD_STARTING_NODE;
4857     aItN = pMeshDS->nodesIterator();
4858     while ( aItN->more() ) {
4859       const SMDS_MeshNode* pNode = aItN->next();
4860       if( pNode==aN1 || pNode==aN2 ) continue;
4861       const SMDS_EdgePosition* pEPos =
4862         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4863       double aT = pEPos->GetUParameter();
4864       aPrms.push_back( aT );
4865     }
4866     //Extrusion_Error err =
4867     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4868   }
4869   else if( aS.ShapeType() == TopAbs_WIRE ) {
4870     list< SMESH_subMesh* > LSM;
4871     TopTools_SequenceOfShape Edges;
4872     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4873     for(; eExp.More(); eExp.Next()) {
4874       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4875       if( BRep_Tool::Degenerated(E) ) continue;
4876       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4877       if(SM) {
4878         LSM.push_back(SM);
4879         Edges.Append(E);
4880       }
4881     }
4882     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4883     int startNid = theN1->GetID();
4884     TColStd_MapOfInteger UsedNums;
4885     int NbEdges = Edges.Length();
4886     int i = 1;
4887     for(; i<=NbEdges; i++) {
4888       int k = 0;
4889       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4890       for(; itLSM!=LSM.end(); itLSM++) {
4891         k++;
4892         if(UsedNums.Contains(k)) continue;
4893         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4894         SMESH_subMesh* locTrack = *itLSM;
4895         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4896         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4897         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4898         const SMDS_MeshNode* aN1 = aItN->next();
4899         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4900         const SMDS_MeshNode* aN2 = aItN->next();
4901         // starting node must be aN1 or aN2
4902         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4903         // 2. Collect parameters on the track edge
4904         aPrms.clear();
4905         aItN = locMeshDS->GetNodes();
4906         while ( aItN->more() ) {
4907           const SMDS_MeshNode* pNode = aItN->next();
4908           const SMDS_EdgePosition* pEPos =
4909             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4910           double aT = pEPos->GetUParameter();
4911           aPrms.push_back( aT );
4912         }
4913         list<SMESH_MeshEditor_PathPoint> LPP;
4914         //Extrusion_Error err =
4915         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4916         LLPPs.push_back(LPP);
4917         UsedNums.Add(k);
4918         // update startN for search following egde
4919         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4920         else startNid = aN1->GetID();
4921         break;
4922       }
4923     }
4924     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4925     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4926     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4927     for(; itPP!=firstList.end(); itPP++) {
4928       fullList.push_back( *itPP );
4929     }
4930     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4931     fullList.pop_back();
4932     itLLPP++;
4933     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4934       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4935       itPP = currList.begin();
4936       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4937       gp_Pnt P1 = PP1.Pnt();
4938       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4939       gp_Pnt P2 = PP2.Pnt();
4940       gp_Dir D1 = PP1.Tangent();
4941       gp_Dir D2 = PP2.Tangent();
4942       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4943                            (D1.Z()+D2.Z())/2 ) );
4944       PP1.SetTangent(Dnew);
4945       fullList.push_back(PP1);
4946       itPP++;
4947       for(; itPP!=currList.end(); itPP++) {
4948         fullList.push_back( *itPP );
4949       }
4950       PP1 = fullList.back();
4951       fullList.pop_back();
4952     }
4953     // if wire not closed
4954     fullList.push_back(PP1);
4955     // else ???
4956   }
4957   else {
4958     return EXTR_BAD_PATH_SHAPE;
4959   }
4960
4961   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4962                           theHasRefPoint, theRefPoint, theMakeGroups);
4963 }
4964
4965
4966 //=======================================================================
4967 //function : MakeEdgePathPoints
4968 //purpose  : auxilary for ExtrusionAlongTrack
4969 //=======================================================================
4970 SMESH_MeshEditor::Extrusion_Error
4971 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4972                                      const TopoDS_Edge& aTrackEdge,
4973                                      bool FirstIsStart,
4974                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4975 {
4976   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4977   aTolVec=1.e-7;
4978   aTolVec2=aTolVec*aTolVec;
4979   double aT1, aT2;
4980   TopoDS_Vertex aV1, aV2;
4981   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4982   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4983   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4984   // 2. Collect parameters on the track edge
4985   aPrms.push_front( aT1 );
4986   aPrms.push_back( aT2 );
4987   // sort parameters
4988   aPrms.sort();
4989   if( FirstIsStart ) {
4990     if ( aT1 > aT2 ) {
4991       aPrms.reverse();
4992     }
4993   }
4994   else {
4995     if ( aT2 > aT1 ) {
4996       aPrms.reverse();
4997     }
4998   }
4999   // 3. Path Points
5000   SMESH_MeshEditor_PathPoint aPP;
5001   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5002   std::list<double>::iterator aItD = aPrms.begin();
5003   for(; aItD != aPrms.end(); ++aItD) {
5004     double aT = *aItD;
5005     gp_Pnt aP3D;
5006     gp_Vec aVec;
5007     aC3D->D1( aT, aP3D, aVec );
5008     aL2 = aVec.SquareMagnitude();
5009     if ( aL2 < aTolVec2 )
5010       return EXTR_CANT_GET_TANGENT;
5011     gp_Dir aTgt( aVec );
5012     aPP.SetPnt( aP3D );
5013     aPP.SetTangent( aTgt );
5014     aPP.SetParameter( aT );
5015     LPP.push_back(aPP);
5016   }
5017   return EXTR_OK;
5018 }
5019
5020
5021 //=======================================================================
5022 //function : MakeExtrElements
5023 //purpose  : auxilary for ExtrusionAlongTrack
5024 //=======================================================================
5025 SMESH_MeshEditor::Extrusion_Error
5026 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5027                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5028                                    const bool theHasAngles,
5029                                    list<double>& theAngles,
5030                                    const bool theLinearVariation,
5031                                    const bool theHasRefPoint,
5032                                    const gp_Pnt& theRefPoint,
5033                                    const bool theMakeGroups)
5034 {
5035   MESSAGE("MakeExtrElements");
5036   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5037   int aNbTP = fullList.size();
5038   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5039   // Angles
5040   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5041     LinearAngleVariation(aNbTP-1, theAngles);
5042   }
5043   vector<double> aAngles( aNbTP );
5044   int j = 0;
5045   for(; j<aNbTP; ++j) {
5046     aAngles[j] = 0.;
5047   }
5048   if ( theHasAngles ) {
5049     double anAngle;;
5050     std::list<double>::iterator aItD = theAngles.begin();
5051     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5052       anAngle = *aItD;
5053       aAngles[j] = anAngle;
5054     }
5055   }
5056   // fill vector of path points with angles
5057   //aPPs.resize(fullList.size());
5058   j = -1;
5059   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5060   for(; itPP!=fullList.end(); itPP++) {
5061     j++;
5062     SMESH_MeshEditor_PathPoint PP = *itPP;
5063     PP.SetAngle(aAngles[j]);
5064     aPPs[j] = PP;
5065   }
5066
5067   TNodeOfNodeListMap mapNewNodes;
5068   TElemOfVecOfNnlmiMap mapElemNewNodes;
5069   TElemOfElemListMap newElemsMap;
5070   TIDSortedElemSet::iterator itElem;
5071   double aX, aY, aZ;
5072   int aNb;
5073   SMDSAbs_ElementType aTypeE;
5074   // source elements for each generated one
5075   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5076
5077   // 3. Center of rotation aV0
5078   gp_Pnt aV0 = theRefPoint;
5079   gp_XYZ aGC;
5080   if ( !theHasRefPoint ) {
5081     aNb = 0;
5082     aGC.SetCoord( 0.,0.,0. );
5083
5084     itElem = theElements.begin();
5085     for ( ; itElem != theElements.end(); itElem++ ) {
5086       const SMDS_MeshElement* elem = *itElem;
5087
5088       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5089       while ( itN->more() ) {
5090         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5091         aX = node->X();
5092         aY = node->Y();
5093         aZ = node->Z();
5094
5095         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5096           list<const SMDS_MeshNode*> aLNx;
5097           mapNewNodes[node] = aLNx;
5098           //
5099           gp_XYZ aXYZ( aX, aY, aZ );
5100           aGC += aXYZ;
5101           ++aNb;
5102         }
5103       }
5104     }
5105     aGC /= aNb;
5106     aV0.SetXYZ( aGC );
5107   } // if (!theHasRefPoint) {
5108   mapNewNodes.clear();
5109
5110   // 4. Processing the elements
5111   SMESHDS_Mesh* aMesh = GetMeshDS();
5112
5113   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5114     // check element type
5115     const SMDS_MeshElement* elem = *itElem;
5116     aTypeE = elem->GetType();
5117     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5118       continue;
5119
5120     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5121     newNodesItVec.reserve( elem->NbNodes() );
5122
5123     // loop on elem nodes
5124     int nodeIndex = -1;
5125     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5126     while ( itN->more() )
5127     {
5128       ++nodeIndex;
5129       // check if a node has been already processed
5130       const SMDS_MeshNode* node =
5131         static_cast<const SMDS_MeshNode*>( itN->next() );
5132       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5133       if ( nIt == mapNewNodes.end() ) {
5134         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5135         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5136
5137         // make new nodes
5138         aX = node->X();  aY = node->Y(); aZ = node->Z();
5139
5140         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5141         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5142         gp_Ax1 anAx1, anAxT1T0;
5143         gp_Dir aDT1x, aDT0x, aDT1T0;
5144
5145         aTolAng=1.e-4;
5146
5147         aV0x = aV0;
5148         aPN0.SetCoord(aX, aY, aZ);
5149
5150         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5151         aP0x = aPP0.Pnt();
5152         aDT0x= aPP0.Tangent();
5153         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5154
5155         for ( j = 1; j < aNbTP; ++j ) {
5156           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5157           aP1x = aPP1.Pnt();
5158           aDT1x = aPP1.Tangent();
5159           aAngle1x = aPP1.Angle();
5160
5161           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5162           // Translation
5163           gp_Vec aV01x( aP0x, aP1x );
5164           aTrsf.SetTranslation( aV01x );
5165
5166           // traslated point
5167           aV1x = aV0x.Transformed( aTrsf );
5168           aPN1 = aPN0.Transformed( aTrsf );
5169
5170           // rotation 1 [ T1,T0 ]
5171           aAngleT1T0=-aDT1x.Angle( aDT0x );
5172           if (fabs(aAngleT1T0) > aTolAng) {
5173             aDT1T0=aDT1x^aDT0x;
5174             anAxT1T0.SetLocation( aV1x );
5175             anAxT1T0.SetDirection( aDT1T0 );
5176             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5177
5178             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5179           }
5180
5181           // rotation 2
5182           if ( theHasAngles ) {
5183             anAx1.SetLocation( aV1x );
5184             anAx1.SetDirection( aDT1x );
5185             aTrsfRot.SetRotation( anAx1, aAngle1x );
5186
5187             aPN1 = aPN1.Transformed( aTrsfRot );
5188           }
5189
5190           // make new node
5191           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5192           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5193             // create additional node
5194             double x = ( aPN1.X() + aPN0.X() )/2.;
5195             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5196             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5197             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5198             myLastCreatedNodes.Append(newNode);
5199             srcNodes.Append( node );
5200             listNewNodes.push_back( newNode );
5201           }
5202           aX = aPN1.X();
5203           aY = aPN1.Y();
5204           aZ = aPN1.Z();
5205           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5206           myLastCreatedNodes.Append(newNode);
5207           srcNodes.Append( node );
5208           listNewNodes.push_back( newNode );
5209
5210           aPN0 = aPN1;
5211           aP0x = aP1x;
5212           aV0x = aV1x;
5213           aDT0x = aDT1x;
5214         }
5215       }
5216
5217       else {
5218         // if current elem is quadratic and current node is not medium
5219         // we have to check - may be it is needed to insert additional nodes
5220         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5221           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5222           if(listNewNodes.size()==aNbTP-1) {
5223             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5224             gp_XYZ P(node->X(), node->Y(), node->Z());
5225             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5226             int i;
5227             for(i=0; i<aNbTP-1; i++) {
5228               const SMDS_MeshNode* N = *it;
5229               double x = ( N->X() + P.X() )/2.;
5230               double y = ( N->Y() + P.Y() )/2.;
5231               double z = ( N->Z() + P.Z() )/2.;
5232               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5233               srcNodes.Append( node );
5234               myLastCreatedNodes.Append(newN);
5235               aNodes[2*i] = newN;
5236               aNodes[2*i+1] = N;
5237               P = gp_XYZ(N->X(),N->Y(),N->Z());
5238             }
5239             listNewNodes.clear();
5240             for(i=0; i<2*(aNbTP-1); i++) {
5241               listNewNodes.push_back(aNodes[i]);
5242             }
5243           }
5244         }
5245       }
5246
5247       newNodesItVec.push_back( nIt );
5248     }
5249     // make new elements
5250     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5251     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5252     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5253   }
5254
5255   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5256
5257   if ( theMakeGroups )
5258     generateGroups( srcNodes, srcElems, "extruded");
5259
5260   return EXTR_OK;
5261 }
5262
5263
5264 //=======================================================================
5265 //function : LinearAngleVariation
5266 //purpose  : auxilary for ExtrusionAlongTrack
5267 //=======================================================================
5268 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5269                                             list<double>& Angles)
5270 {
5271   int nbAngles = Angles.size();
5272   if( nbSteps > nbAngles ) {
5273     vector<double> theAngles(nbAngles);
5274     list<double>::iterator it = Angles.begin();
5275     int i = -1;
5276     for(; it!=Angles.end(); it++) {
5277       i++;
5278       theAngles[i] = (*it);
5279     }
5280     list<double> res;
5281     double rAn2St = double( nbAngles ) / double( nbSteps );
5282     double angPrev = 0, angle;
5283     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5284       double angCur = rAn2St * ( iSt+1 );
5285       double angCurFloor  = floor( angCur );
5286       double angPrevFloor = floor( angPrev );
5287       if ( angPrevFloor == angCurFloor )
5288         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5289       else {
5290         int iP = int( angPrevFloor );
5291         double angPrevCeil = ceil(angPrev);
5292         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5293
5294         int iC = int( angCurFloor );
5295         if ( iC < nbAngles )
5296           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5297
5298         iP = int( angPrevCeil );
5299         while ( iC-- > iP )
5300           angle += theAngles[ iC ];
5301       }
5302       res.push_back(angle);
5303       angPrev = angCur;
5304     }
5305     Angles.clear();
5306     it = res.begin();
5307     for(; it!=res.end(); it++)
5308       Angles.push_back( *it );
5309   }
5310 }
5311
5312
5313 //================================================================================
5314 /*!
5315  * \brief Move or copy theElements applying theTrsf to their nodes
5316  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5317  *  \param theTrsf - transformation to apply
5318  *  \param theCopy - if true, create translated copies of theElems
5319  *  \param theMakeGroups - if true and theCopy, create translated groups
5320  *  \param theTargetMesh - mesh to copy translated elements into
5321  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5322  */
5323 //================================================================================
5324
5325 SMESH_MeshEditor::PGroupIDs
5326 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5327                              const gp_Trsf&     theTrsf,
5328                              const bool         theCopy,
5329                              const bool         theMakeGroups,
5330                              SMESH_Mesh*        theTargetMesh)
5331 {
5332   myLastCreatedElems.Clear();
5333   myLastCreatedNodes.Clear();
5334
5335   bool needReverse = false;
5336   string groupPostfix;
5337   switch ( theTrsf.Form() ) {
5338   case gp_PntMirror:
5339     MESSAGE("gp_PntMirror");
5340     needReverse = true;
5341     groupPostfix = "mirrored";
5342     break;
5343   case gp_Ax1Mirror:
5344     MESSAGE("gp_Ax1Mirror");
5345     groupPostfix = "mirrored";
5346     break;
5347   case gp_Ax2Mirror:
5348     MESSAGE("gp_Ax2Mirror");
5349     needReverse = true;
5350     groupPostfix = "mirrored";
5351     break;
5352   case gp_Rotation:
5353     MESSAGE("gp_Rotation");
5354     groupPostfix = "rotated";
5355     break;
5356   case gp_Translation:
5357     MESSAGE("gp_Translation");
5358     groupPostfix = "translated";
5359     break;
5360   case gp_Scale:
5361     MESSAGE("gp_Scale");
5362     groupPostfix = "scaled";
5363     break;
5364   case gp_CompoundTrsf: // different scale by axis
5365     MESSAGE("gp_CompoundTrsf");
5366     groupPostfix = "scaled";
5367     break;
5368   default:
5369     MESSAGE("default");
5370     needReverse = false;
5371     groupPostfix = "transformed";
5372   }
5373
5374   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5375   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5376   SMESHDS_Mesh* aMesh    = GetMeshDS();
5377
5378
5379   // map old node to new one
5380   TNodeNodeMap nodeMap;
5381
5382   // elements sharing moved nodes; those of them which have all
5383   // nodes mirrored but are not in theElems are to be reversed
5384   TIDSortedElemSet inverseElemSet;
5385
5386   // source elements for each generated one
5387   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5388
5389   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5390   TIDSortedElemSet orphanNode;
5391
5392   if ( theElems.empty() ) // transform the whole mesh
5393   {
5394     // add all elements
5395     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5396     while ( eIt->more() ) theElems.insert( eIt->next() );
5397     // add orphan nodes
5398     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5399     while ( nIt->more() )
5400     {
5401       const SMDS_MeshNode* node = nIt->next();
5402       if ( node->NbInverseElements() == 0)
5403         orphanNode.insert( node );
5404     }
5405   }
5406
5407   // loop on elements to transform nodes : first orphan nodes then elems
5408   TIDSortedElemSet::iterator itElem;
5409   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5410   for (int i=0; i<2; i++)
5411   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5412     const SMDS_MeshElement* elem = *itElem;
5413     if ( !elem )
5414       continue;
5415
5416     // loop on elem nodes
5417     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5418     while ( itN->more() ) {
5419
5420       const SMDS_MeshNode* node = cast2Node( itN->next() );
5421       // check if a node has been already transformed
5422       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5423         nodeMap.insert( make_pair ( node, node ));
5424       if ( !n2n_isnew.second )
5425         continue;
5426
5427       double coord[3];
5428       coord[0] = node->X();
5429       coord[1] = node->Y();
5430       coord[2] = node->Z();
5431       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5432       if ( theTargetMesh ) {
5433         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5434         n2n_isnew.first->second = newNode;
5435         myLastCreatedNodes.Append(newNode);
5436         srcNodes.Append( node );
5437       }
5438       else if ( theCopy ) {
5439         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5440         n2n_isnew.first->second = newNode;
5441         myLastCreatedNodes.Append(newNode);
5442         srcNodes.Append( node );
5443       }
5444       else {
5445         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5446         // node position on shape becomes invalid
5447         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5448           ( SMDS_SpacePosition::originSpacePosition() );
5449       }
5450
5451       // keep inverse elements
5452       if ( !theCopy && !theTargetMesh && needReverse ) {
5453         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5454         while ( invElemIt->more() ) {
5455           const SMDS_MeshElement* iel = invElemIt->next();
5456           inverseElemSet.insert( iel );
5457         }
5458       }
5459     }
5460   }
5461
5462   // either create new elements or reverse mirrored ones
5463   if ( !theCopy && !needReverse && !theTargetMesh )
5464     return PGroupIDs();
5465
5466   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5467   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5468     theElems.insert( *invElemIt );
5469
5470   // replicate or reverse elements
5471   // TODO revoir ordre reverse vtk
5472   enum {
5473     REV_TETRA   = 0,  //  = nbNodes - 4
5474     REV_PYRAMID = 1,  //  = nbNodes - 4
5475     REV_PENTA   = 2,  //  = nbNodes - 4
5476     REV_FACE    = 3,
5477     REV_HEXA    = 4,  //  = nbNodes - 4
5478     FORWARD     = 5
5479   };
5480   int index[][8] = {
5481     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5482     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5483     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5484     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5485     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5486     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5487   };
5488
5489   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5490   {
5491     const SMDS_MeshElement* elem = *itElem;
5492     if ( !elem || elem->GetType() == SMDSAbs_Node )
5493       continue;
5494
5495     int nbNodes = elem->NbNodes();
5496     int elemType = elem->GetType();
5497
5498     if (elem->IsPoly()) {
5499       // Polygon or Polyhedral Volume
5500       switch ( elemType ) {
5501       case SMDSAbs_Face:
5502         {
5503           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5504           int iNode = 0;
5505           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5506           while (itN->more()) {
5507             const SMDS_MeshNode* node =
5508               static_cast<const SMDS_MeshNode*>(itN->next());
5509             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5510             if (nodeMapIt == nodeMap.end())
5511               break; // not all nodes transformed
5512             if (needReverse) {
5513               // reverse mirrored faces and volumes
5514               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5515             } else {
5516               poly_nodes[iNode] = (*nodeMapIt).second;
5517             }
5518             iNode++;
5519           }
5520           if ( iNode != nbNodes )
5521             continue; // not all nodes transformed
5522
5523           if ( theTargetMesh ) {
5524             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5525             srcElems.Append( elem );
5526           }
5527           else if ( theCopy ) {
5528             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5529             srcElems.Append( elem );
5530           }
5531           else {
5532             aMesh->ChangePolygonNodes(elem, poly_nodes);
5533           }
5534         }
5535         break;
5536       case SMDSAbs_Volume:
5537         {
5538           // ATTENTION: Reversing is not yet done!!!
5539           const SMDS_VtkVolume* aPolyedre =
5540             dynamic_cast<const SMDS_VtkVolume*>( elem );
5541           if (!aPolyedre) {
5542             MESSAGE("Warning: bad volumic element");
5543             continue;
5544           }
5545
5546           vector<const SMDS_MeshNode*> poly_nodes;
5547           vector<int> quantities;
5548
5549           bool allTransformed = true;
5550           int nbFaces = aPolyedre->NbFaces();
5551           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5552             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5553             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5554               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5555               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5556               if (nodeMapIt == nodeMap.end()) {
5557                 allTransformed = false; // not all nodes transformed
5558               } else {
5559                 poly_nodes.push_back((*nodeMapIt).second);
5560               }
5561             }
5562             quantities.push_back(nbFaceNodes);
5563           }
5564           if ( !allTransformed )
5565             continue; // not all nodes transformed
5566
5567           if ( theTargetMesh ) {
5568             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5569             srcElems.Append( elem );
5570           }
5571           else if ( theCopy ) {
5572             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5573             srcElems.Append( elem );
5574           }
5575           else {
5576             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5577           }
5578         }
5579         break;
5580       default:;
5581       }
5582       continue;
5583     }
5584
5585     // Regular elements
5586     int* i = index[ FORWARD ];
5587     if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5588       if ( elemType == SMDSAbs_Face )
5589         i = index[ REV_FACE ];
5590       else
5591         i = index[ nbNodes - 4 ];
5592     }
5593     if(elem->IsQuadratic()) {
5594       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5595       i = anIds;
5596       if(needReverse) {
5597         if(nbNodes==3) { // quadratic edge
5598           static int anIds[] = {1,0,2};
5599           i = anIds;
5600         }
5601         else if(nbNodes==6) { // quadratic triangle
5602           static int anIds[] = {0,2,1,5,4,3};
5603           i = anIds;
5604         }
5605         else if(nbNodes==8) { // quadratic quadrangle
5606           static int anIds[] = {0,3,2,1,7,6,5,4};
5607           i = anIds;
5608         }
5609         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5610           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5611           i = anIds;
5612         }
5613         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5614           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5615           i = anIds;
5616         }
5617         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5618           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5619           i = anIds;
5620         }
5621         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5622           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5623           i = anIds;
5624         }
5625       }
5626     }
5627
5628     // find transformed nodes
5629     vector<const SMDS_MeshNode*> nodes(nbNodes);
5630     int iNode = 0;
5631     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5632     while ( itN->more() ) {
5633       const SMDS_MeshNode* node =
5634         static_cast<const SMDS_MeshNode*>( itN->next() );
5635       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5636       if ( nodeMapIt == nodeMap.end() )
5637         break; // not all nodes transformed
5638       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5639     }
5640     if ( iNode != nbNodes )
5641       continue; // not all nodes transformed
5642
5643     if ( theTargetMesh ) {
5644       if ( SMDS_MeshElement* copy =
5645            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5646         myLastCreatedElems.Append( copy );
5647         srcElems.Append( elem );
5648       }
5649     }
5650     else if ( theCopy ) {
5651       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5652         srcElems.Append( elem );
5653     }
5654     else {
5655       // reverse element as it was reversed by transformation
5656       if ( nbNodes > 2 )
5657         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5658     }
5659   }
5660
5661   PGroupIDs newGroupIDs;
5662
5663   if ( theMakeGroups && theCopy ||
5664        theMakeGroups && theTargetMesh )
5665     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5666
5667   return newGroupIDs;
5668 }
5669
5670
5671 ////=======================================================================
5672 ////function : Scale
5673 ////purpose  :
5674 ////=======================================================================
5675 //
5676 //SMESH_MeshEditor::PGroupIDs
5677 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5678 //                         const gp_Pnt&            thePoint,
5679 //                         const std::list<double>& theScaleFact,
5680 //                         const bool         theCopy,
5681 //                         const bool         theMakeGroups,
5682 //                         SMESH_Mesh*        theTargetMesh)
5683 //{
5684 //  MESSAGE("Scale");
5685 //  myLastCreatedElems.Clear();
5686 //  myLastCreatedNodes.Clear();
5687 //
5688 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5689 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5690 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
5691 //
5692 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5693 //  std::list<double>::const_iterator itS = theScaleFact.begin();
5694 //  scaleX = (*itS);
5695 //  if(theScaleFact.size()==1) {
5696 //    scaleY = (*itS);
5697 //    scaleZ= (*itS);
5698 //  }
5699 //  if(theScaleFact.size()==2) {
5700 //    itS++;
5701 //    scaleY = (*itS);
5702 //    scaleZ= (*itS);
5703 //  }
5704 //  if(theScaleFact.size()>2) {
5705 //    itS++;
5706 //    scaleY = (*itS);
5707 //    itS++;
5708 //    scaleZ= (*itS);
5709 //  }
5710 //
5711 //  // map old node to new one
5712 //  TNodeNodeMap nodeMap;
5713 //
5714 //  // elements sharing moved nodes; those of them which have all
5715 //  // nodes mirrored but are not in theElems are to be reversed
5716 //  TIDSortedElemSet inverseElemSet;
5717 //
5718 //  // source elements for each generated one
5719 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
5720 //
5721 //  // loop on theElems
5722 //  TIDSortedElemSet::iterator itElem;
5723 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5724 //    const SMDS_MeshElement* elem = *itElem;
5725 //    if ( !elem )
5726 //      continue;
5727 //
5728 //    // loop on elem nodes
5729 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5730 //    while ( itN->more() ) {
5731 //
5732 //      // check if a node has been already transformed
5733 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
5734 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5735 //        nodeMap.insert( make_pair ( node, node ));
5736 //      if ( !n2n_isnew.second )
5737 //        continue;
5738 //
5739 //      //double coord[3];
5740 //      //coord[0] = node->X();
5741 //      //coord[1] = node->Y();
5742 //      //coord[2] = node->Z();
5743 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5744 //      double dx = (node->X() - thePoint.X()) * scaleX;
5745 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
5746 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
5747 //      if ( theTargetMesh ) {
5748 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5749 //        const SMDS_MeshNode * newNode =
5750 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5751 //        n2n_isnew.first->second = newNode;
5752 //        myLastCreatedNodes.Append(newNode);
5753 //        srcNodes.Append( node );
5754 //      }
5755 //      else if ( theCopy ) {
5756 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5757 //        const SMDS_MeshNode * newNode =
5758 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5759 //        n2n_isnew.first->second = newNode;
5760 //        myLastCreatedNodes.Append(newNode);
5761 //        srcNodes.Append( node );
5762 //      }
5763 //      else {
5764 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5765 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5766 //        // node position on shape becomes invalid
5767 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
5768 //          ( SMDS_SpacePosition::originSpacePosition() );
5769 //      }
5770 //
5771 //      // keep inverse elements
5772 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
5773 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5774 //      //  while ( invElemIt->more() ) {
5775 //      //    const SMDS_MeshElement* iel = invElemIt->next();
5776 //      //    inverseElemSet.insert( iel );
5777 //      //  }
5778 //      //}
5779 //    }
5780 //  }
5781 //
5782 //  // either create new elements or reverse mirrored ones
5783 //  //if ( !theCopy && !needReverse && !theTargetMesh )
5784 //  if ( !theCopy && !theTargetMesh )
5785 //    return PGroupIDs();
5786 //
5787 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5788 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5789 //    theElems.insert( *invElemIt );
5790 //
5791 //  // replicate or reverse elements
5792 //
5793 //  enum {
5794 //    REV_TETRA   = 0,  //  = nbNodes - 4
5795 //    REV_PYRAMID = 1,  //  = nbNodes - 4
5796 //    REV_PENTA   = 2,  //  = nbNodes - 4
5797 //    REV_FACE    = 3,
5798 //    REV_HEXA    = 4,  //  = nbNodes - 4
5799 //    FORWARD     = 5
5800 //  };
5801 //  int index[][8] = {
5802 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5803 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5804 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5805 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5806 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5807 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5808 //  };
5809 //
5810 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5811 //  {
5812 //    const SMDS_MeshElement* elem = *itElem;
5813 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
5814 //      continue;
5815 //
5816 //    int nbNodes = elem->NbNodes();
5817 //    int elemType = elem->GetType();
5818 //
5819 //    if (elem->IsPoly()) {
5820 //      // Polygon or Polyhedral Volume
5821 //      switch ( elemType ) {
5822 //      case SMDSAbs_Face:
5823 //        {
5824 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5825 //          int iNode = 0;
5826 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5827 //          while (itN->more()) {
5828 //            const SMDS_MeshNode* node =
5829 //              static_cast<const SMDS_MeshNode*>(itN->next());
5830 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5831 //            if (nodeMapIt == nodeMap.end())
5832 //              break; // not all nodes transformed
5833 //            //if (needReverse) {
5834 //            //  // reverse mirrored faces and volumes
5835 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5836 //            //} else {
5837 //            poly_nodes[iNode] = (*nodeMapIt).second;
5838 //            //}
5839 //            iNode++;
5840 //          }
5841 //          if ( iNode != nbNodes )
5842 //            continue; // not all nodes transformed
5843 //
5844 //          if ( theTargetMesh ) {
5845 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5846 //            srcElems.Append( elem );
5847 //          }
5848 //          else if ( theCopy ) {
5849 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5850 //            srcElems.Append( elem );
5851 //          }
5852 //          else {
5853 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
5854 //          }
5855 //        }
5856 //        break;
5857 //      case SMDSAbs_Volume:
5858 //        {
5859 //          // ATTENTION: Reversing is not yet done!!!
5860 //          const SMDS_VtkVolume* aPolyedre =
5861 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
5862 //          if (!aPolyedre) {
5863 //            MESSAGE("Warning: bad volumic element");
5864 //            continue;
5865 //          }
5866 //
5867 //          vector<const SMDS_MeshNode*> poly_nodes;
5868 //          vector<int> quantities;
5869 //
5870 //          bool allTransformed = true;
5871 //          int nbFaces = aPolyedre->NbFaces();
5872 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5873 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5874 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5875 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5876 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5877 //              if (nodeMapIt == nodeMap.end()) {
5878 //                allTransformed = false; // not all nodes transformed
5879 //              } else {
5880 //                poly_nodes.push_back((*nodeMapIt).second);
5881 //              }
5882 //            }
5883 //            quantities.push_back(nbFaceNodes);
5884 //          }
5885 //          if ( !allTransformed )
5886 //            continue; // not all nodes transformed
5887 //
5888 //          if ( theTargetMesh ) {
5889 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5890 //            srcElems.Append( elem );
5891 //          }
5892 //          else if ( theCopy ) {
5893 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5894 //            srcElems.Append( elem );
5895 //          }
5896 //          else {
5897 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5898 //          }
5899 //        }
5900 //        break;
5901 //      default:;
5902 //      }
5903 //      continue;
5904 //    }
5905 //
5906 //    // Regular elements
5907 //    int* i = index[ FORWARD ];
5908 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5909 //    //  if ( elemType == SMDSAbs_Face )
5910 //    //    i = index[ REV_FACE ];
5911 //    //  else
5912 //    //    i = index[ nbNodes - 4 ];
5913 //
5914 //    if(elem->IsQuadratic()) {
5915 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5916 //      i = anIds;
5917 //      //if(needReverse) {
5918 //      //  if(nbNodes==3) { // quadratic edge
5919 //      //    static int anIds[] = {1,0,2};
5920 //      //    i = anIds;
5921 //      //  }
5922 //      //  else if(nbNodes==6) { // quadratic triangle
5923 //      //    static int anIds[] = {0,2,1,5,4,3};
5924 //      //    i = anIds;
5925 //      //  }
5926 //      //  else if(nbNodes==8) { // quadratic quadrangle
5927 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
5928 //      //    i = anIds;
5929 //      //  }
5930 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5931 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5932 //      //    i = anIds;
5933 //      //  }
5934 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5935 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5936 //      //    i = anIds;
5937 //      //  }
5938 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5939 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5940 //      //    i = anIds;
5941 //      //  }
5942 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5943 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5944 //      //    i = anIds;
5945 //      //  }
5946 //      //}
5947 //    }
5948 //
5949 //    // find transformed nodes
5950 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
5951 //    int iNode = 0;
5952 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5953 //    while ( itN->more() ) {
5954 //      const SMDS_MeshNode* node =
5955 //        static_cast<const SMDS_MeshNode*>( itN->next() );
5956 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5957 //      if ( nodeMapIt == nodeMap.end() )
5958 //        break; // not all nodes transformed
5959 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5960 //    }
5961 //    if ( iNode != nbNodes )
5962 //      continue; // not all nodes transformed
5963 //
5964 //    if ( theTargetMesh ) {
5965 //      if ( SMDS_MeshElement* copy =
5966 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5967 //        myLastCreatedElems.Append( copy );
5968 //        srcElems.Append( elem );
5969 //      }
5970 //    }
5971 //    else if ( theCopy ) {
5972 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5973 //        myLastCreatedElems.Append( copy );
5974 //        srcElems.Append( elem );
5975 //      }
5976 //    }
5977 //    else {
5978 //      // reverse element as it was reversed by transformation
5979 //      if ( nbNodes > 2 )
5980 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5981 //    }
5982 //  }
5983 //
5984 //  PGroupIDs newGroupIDs;
5985 //
5986 //  if ( theMakeGroups && theCopy ||
5987 //       theMakeGroups && theTargetMesh ) {
5988 //    string groupPostfix = "scaled";
5989 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5990 //  }
5991 //
5992 //  return newGroupIDs;
5993 //}
5994
5995
5996 //=======================================================================
5997 /*!
5998  * \brief Create groups of elements made during transformation
5999  * \param nodeGens - nodes making corresponding myLastCreatedNodes
6000  * \param elemGens - elements making corresponding myLastCreatedElems
6001  * \param postfix - to append to names of new groups
6002  */
6003 //=======================================================================
6004
6005 SMESH_MeshEditor::PGroupIDs
6006 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
6007                                  const SMESH_SequenceOfElemPtr& elemGens,
6008                                  const std::string&             postfix,
6009                                  SMESH_Mesh*                    targetMesh)
6010 {
6011   PGroupIDs newGroupIDs( new list<int> );
6012   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6013
6014   // Sort existing groups by types and collect their names
6015
6016   // to store an old group and a generated new one
6017   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6018   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6019   // group names
6020   set< string > groupNames;
6021   //
6022   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6023   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6024   while ( groupIt->more() ) {
6025     SMESH_Group * group = groupIt->next();
6026     if ( !group ) continue;
6027     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6028     if ( !groupDS || groupDS->IsEmpty() ) continue;
6029     groupNames.insert( group->GetName() );
6030     groupDS->SetStoreName( group->GetName() );
6031     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6032   }
6033
6034   // Groups creation
6035
6036   // loop on nodes and elements
6037   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6038   {
6039     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6040     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6041     if ( gens.Length() != elems.Length() )
6042       throw SALOME_Exception(LOCALIZED("invalid args"));
6043
6044     // loop on created elements
6045     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6046     {
6047       const SMDS_MeshElement* sourceElem = gens( iElem );
6048       if ( !sourceElem ) {
6049         MESSAGE("generateGroups(): NULL source element");
6050         continue;
6051       }
6052       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6053       if ( groupsOldNew.empty() ) {
6054         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6055           ++iElem; // skip all elements made by sourceElem
6056         continue;
6057       }
6058       // collect all elements made by sourceElem
6059       list< const SMDS_MeshElement* > resultElems;
6060       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6061         if ( resElem != sourceElem )
6062           resultElems.push_back( resElem );
6063       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6064         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6065           if ( resElem != sourceElem )
6066             resultElems.push_back( resElem );
6067       // do not generate element groups from node ones
6068       if ( sourceElem->GetType() == SMDSAbs_Node &&
6069            elems( iElem )->GetType() != SMDSAbs_Node )
6070         continue;
6071
6072       // add resultElems to groups made by ones the sourceElem belongs to
6073       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6074       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6075       {
6076         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6077         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6078         {
6079           SMDS_MeshGroup* & newGroup = gOldNew->second;
6080           if ( !newGroup )// create a new group
6081           {
6082             // make a name
6083             string name = oldGroup->GetStoreName();
6084             if ( !targetMesh ) {
6085               name += "_";
6086               name += postfix;
6087               int nb = 0;
6088               while ( !groupNames.insert( name ).second ) // name exists
6089               {
6090                 if ( nb == 0 ) {
6091                   name += "_1";
6092                 }
6093                 else {
6094                   TCollection_AsciiString nbStr(nb+1);
6095                   name.resize( name.rfind('_')+1 );
6096                   name += nbStr.ToCString();
6097                 }
6098                 ++nb;
6099               }
6100             }
6101             // make a group
6102             int id;
6103             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6104                                                  name.c_str(), id );
6105             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6106             newGroup = & groupDS->SMDSGroup();
6107             newGroupIDs->push_back( id );
6108           }
6109
6110           // fill in a new group
6111           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6112           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6113             newGroup->Add( *resElemIt );
6114         }
6115       }
6116     } // loop on created elements
6117   }// loop on nodes and elements
6118
6119   return newGroupIDs;
6120 }
6121
6122 //================================================================================
6123 /*!
6124  * \brief Return list of group of nodes close to each other within theTolerance
6125  *        Search among theNodes or in the whole mesh if theNodes is empty using
6126  *        an Octree algorithm
6127  */
6128 //================================================================================
6129
6130 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6131                                             const double         theTolerance,
6132                                             TListOfListOfNodes & theGroupsOfNodes)
6133 {
6134   myLastCreatedElems.Clear();
6135   myLastCreatedNodes.Clear();
6136
6137   if ( theNodes.empty() )
6138   { // get all nodes in the mesh
6139     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6140     while ( nIt->more() )
6141       theNodes.insert( theNodes.end(),nIt->next());
6142   }
6143
6144   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6145 }
6146
6147
6148 //=======================================================================
6149 /*!
6150  * \brief Implementation of search for the node closest to point
6151  */
6152 //=======================================================================
6153
6154 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6155 {
6156   //---------------------------------------------------------------------
6157   /*!
6158    * \brief Constructor
6159    */
6160   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6161   {
6162     myMesh = ( SMESHDS_Mesh* ) theMesh;
6163
6164     TIDSortedNodeSet nodes;
6165     if ( theMesh ) {
6166       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6167       while ( nIt->more() )
6168         nodes.insert( nodes.end(), nIt->next() );
6169     }
6170     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6171
6172     // get max size of a leaf box
6173     SMESH_OctreeNode* tree = myOctreeNode;
6174     while ( !tree->isLeaf() )
6175     {
6176       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6177       if ( cIt->more() )
6178         tree = cIt->next();
6179     }
6180     myHalfLeafSize = tree->maxSize() / 2.;
6181   }
6182
6183   //---------------------------------------------------------------------
6184   /*!
6185    * \brief Move node and update myOctreeNode accordingly
6186    */
6187   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6188   {
6189     myOctreeNode->UpdateByMoveNode( node, toPnt );
6190     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6191   }
6192
6193   //---------------------------------------------------------------------
6194   /*!
6195    * \brief Do it's job
6196    */
6197   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6198   {
6199     map<double, const SMDS_MeshNode*> dist2Nodes;
6200     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6201     if ( !dist2Nodes.empty() )
6202       return dist2Nodes.begin()->second;
6203     list<const SMDS_MeshNode*> nodes;
6204     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6205
6206     double minSqDist = DBL_MAX;
6207     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6208     {
6209       // sort leafs by their distance from thePnt
6210       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6211       TDistTreeMap treeMap;
6212       list< SMESH_OctreeNode* > treeList;
6213       list< SMESH_OctreeNode* >::iterator trIt;
6214       treeList.push_back( myOctreeNode );
6215
6216       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6217       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6218       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6219       {
6220         SMESH_OctreeNode* tree = *trIt;
6221         if ( !tree->isLeaf() ) // put children to the queue
6222         {
6223           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6224           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6225           while ( cIt->more() )
6226             treeList.push_back( cIt->next() );
6227         }
6228         else if ( tree->NbNodes() ) // put a tree to the treeMap
6229         {
6230           const Bnd_B3d& box = tree->getBox();
6231           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6232           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6233           if ( !it_in.second ) // not unique distance to box center
6234             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6235         }
6236       }
6237       // find distance after which there is no sense to check tree's
6238       double sqLimit = DBL_MAX;
6239       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6240       if ( treeMap.size() > 5 ) {
6241         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6242         const Bnd_B3d& box = closestTree->getBox();
6243         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6244         sqLimit = limit * limit;
6245       }
6246       // get all nodes from trees
6247       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6248         if ( sqDist_tree->first > sqLimit )
6249           break;
6250         SMESH_OctreeNode* tree = sqDist_tree->second;
6251         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6252       }
6253     }
6254     // find closest among nodes
6255     minSqDist = DBL_MAX;
6256     const SMDS_MeshNode* closestNode = 0;
6257     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6258     for ( ; nIt != nodes.end(); ++nIt ) {
6259       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6260       if ( minSqDist > sqDist ) {
6261         closestNode = *nIt;
6262         minSqDist = sqDist;
6263       }
6264     }
6265     return closestNode;
6266   }
6267
6268   //---------------------------------------------------------------------
6269   /*!
6270    * \brief Destructor
6271    */
6272   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6273
6274   //---------------------------------------------------------------------
6275   /*!
6276    * \brief Return the node tree
6277    */
6278   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6279
6280 private:
6281   SMESH_OctreeNode* myOctreeNode;
6282   SMESHDS_Mesh*     myMesh;
6283   double            myHalfLeafSize; // max size of a leaf box
6284 };
6285
6286 //=======================================================================
6287 /*!
6288  * \brief Return SMESH_NodeSearcher
6289  */
6290 //=======================================================================
6291
6292 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6293 {
6294   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6295 }
6296
6297 // ========================================================================
6298 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6299 {
6300   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6301   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6302   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6303
6304   //=======================================================================
6305   /*!
6306    * \brief Octal tree of bounding boxes of elements
6307    */
6308   //=======================================================================
6309
6310   class ElementBndBoxTree : public SMESH_Octree
6311   {
6312   public:
6313
6314     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6315     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6316     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6317     ~ElementBndBoxTree();
6318
6319   protected:
6320     ElementBndBoxTree() {}
6321     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6322     void buildChildrenData();
6323     Bnd_B3d* buildRootBox();
6324   private:
6325     //!< Bounding box of element
6326     struct ElementBox : public Bnd_B3d
6327     {
6328       const SMDS_MeshElement* _element;
6329       int                     _refCount; // an ElementBox can be included in several tree branches
6330       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6331     };
6332     vector< ElementBox* > _elements;
6333   };
6334
6335   //================================================================================
6336   /*!
6337    * \brief ElementBndBoxTree creation
6338    */
6339   //================================================================================
6340
6341   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6342     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6343   {
6344     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6345     _elements.reserve( nbElems );
6346
6347     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6348     while ( elemIt->more() )
6349       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6350
6351     if ( _elements.size() > MaxNbElemsInLeaf )
6352       compute();
6353     else
6354       myIsLeaf = true;
6355   }
6356
6357   //================================================================================
6358   /*!
6359    * \brief Destructor
6360    */
6361   //================================================================================
6362
6363   ElementBndBoxTree::~ElementBndBoxTree()
6364   {
6365     for ( int i = 0; i < _elements.size(); ++i )
6366       if ( --_elements[i]->_refCount <= 0 )
6367         delete _elements[i];
6368   }
6369
6370   //================================================================================
6371   /*!
6372    * \brief Return the maximal box
6373    */
6374   //================================================================================
6375
6376   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6377   {
6378     Bnd_B3d* box = new Bnd_B3d;
6379     for ( int i = 0; i < _elements.size(); ++i )
6380       box->Add( *_elements[i] );
6381     return box;
6382   }
6383
6384   //================================================================================
6385   /*!
6386    * \brief Redistrubute element boxes among children
6387    */
6388   //================================================================================
6389
6390   void ElementBndBoxTree::buildChildrenData()
6391   {
6392     for ( int i = 0; i < _elements.size(); ++i )
6393     {
6394       for (int j = 0; j < 8; j++)
6395       {
6396         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6397         {
6398           _elements[i]->_refCount++;
6399           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6400         }
6401       }
6402       _elements[i]->_refCount--;
6403     }
6404     _elements.clear();
6405
6406     for (int j = 0; j < 8; j++)
6407     {
6408       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6409       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6410         child->myIsLeaf = true;
6411
6412       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6413         child->_elements.resize( child->_elements.size() ); // compact
6414     }
6415   }
6416
6417   //================================================================================
6418   /*!
6419    * \brief Return elements which can include the point
6420    */
6421   //================================================================================
6422
6423   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6424                                                 TIDSortedElemSet& foundElems)
6425   {
6426     if ( level() && getBox().IsOut( point.XYZ() ))
6427       return;
6428
6429     if ( isLeaf() )
6430     {
6431       for ( int i = 0; i < _elements.size(); ++i )
6432         if ( !_elements[i]->IsOut( point.XYZ() ))
6433           foundElems.insert( _elements[i]->_element );
6434     }
6435     else
6436     {
6437       for (int i = 0; i < 8; i++)
6438         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6439     }
6440   }
6441
6442   //================================================================================
6443   /*!
6444    * \brief Return elements which can be intersected by the line
6445    */
6446   //================================================================================
6447
6448   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6449                                                TIDSortedElemSet& foundElems)
6450   {
6451     if ( level() && getBox().IsOut( line ))
6452       return;
6453
6454     if ( isLeaf() )
6455     {
6456       for ( int i = 0; i < _elements.size(); ++i )
6457         if ( !_elements[i]->IsOut( line ))
6458           foundElems.insert( _elements[i]->_element );
6459     }
6460     else
6461     {
6462       for (int i = 0; i < 8; i++)
6463         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6464     }
6465   }
6466
6467   //================================================================================
6468   /*!
6469    * \brief Construct the element box
6470    */
6471   //================================================================================
6472
6473   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6474   {
6475     _element  = elem;
6476     _refCount = 1;
6477     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6478     while ( nIt->more() )
6479       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6480     Enlarge( tolerance );
6481   }
6482
6483 } // namespace
6484
6485 //=======================================================================
6486 /*!
6487  * \brief Implementation of search for the elements by point and
6488  *        of classification of point in 2D mesh
6489  */
6490 //=======================================================================
6491
6492 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6493 {
6494   SMESHDS_Mesh*                _mesh;
6495   SMDS_ElemIteratorPtr         _meshPartIt;
6496   ElementBndBoxTree*           _ebbTree;
6497   SMESH_NodeSearcherImpl*      _nodeSearcher;
6498   SMDSAbs_ElementType          _elementType;
6499   double                       _tolerance;
6500   bool                         _outerFacesFound;
6501   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6502
6503   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6504     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6505   ~SMESH_ElementSearcherImpl()
6506   {
6507     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6508     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6509   }
6510   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6511                                   SMDSAbs_ElementType                type,
6512                                   vector< const SMDS_MeshElement* >& foundElements);
6513   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6514
6515   void GetElementsNearLine( const gp_Ax1&                      line,
6516                             SMDSAbs_ElementType                type,
6517                             vector< const SMDS_MeshElement* >& foundElems);
6518   double getTolerance();
6519   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6520                             const double tolerance, double & param);
6521   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6522   bool isOuterBoundary(const SMDS_MeshElement* face) const
6523   {
6524     return _outerFaces.empty() || _outerFaces.count(face);
6525   }
6526   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6527   {
6528     const SMDS_MeshElement* _face;
6529     gp_Vec                  _faceNorm;
6530     bool                    _coincides; //!< the line lays in face plane
6531     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6532       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6533   };
6534   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6535   {
6536     SMESH_TLink      _link;
6537     TIDSortedElemSet _faces;
6538     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6539       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6540   };
6541 };
6542
6543 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6544 {
6545   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6546              << ", _coincides="<<i._coincides << ")";
6547 }
6548
6549 //=======================================================================
6550 /*!
6551  * \brief define tolerance for search
6552  */
6553 //=======================================================================
6554
6555 double SMESH_ElementSearcherImpl::getTolerance()
6556 {
6557   if ( _tolerance < 0 )
6558   {
6559     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6560
6561     _tolerance = 0;
6562     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6563     {
6564       double boxSize = _nodeSearcher->getTree()->maxSize();
6565       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6566     }
6567     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6568     {
6569       double boxSize = _ebbTree->maxSize();
6570       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6571     }
6572     if ( _tolerance == 0 )
6573     {
6574       // define tolerance by size of a most complex element
6575       int complexType = SMDSAbs_Volume;
6576       while ( complexType > SMDSAbs_All &&
6577               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6578         --complexType;
6579       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6580       double elemSize;
6581       if ( complexType == int( SMDSAbs_Node ))
6582       {
6583         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6584         elemSize = 1;
6585         if ( meshInfo.NbNodes() > 2 )
6586           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6587       }
6588       else
6589       {
6590         SMDS_ElemIteratorPtr elemIt =
6591             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6592         const SMDS_MeshElement* elem = elemIt->next();
6593         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6594         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6595         elemSize = 0;
6596         while ( nodeIt->more() )
6597         {
6598           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6599           elemSize = max( dist, elemSize );
6600         }
6601       }
6602       _tolerance = 1e-4 * elemSize;
6603     }
6604   }
6605   return _tolerance;
6606 }
6607
6608 //================================================================================
6609 /*!
6610  * \brief Find intersection of the line and an edge of face and return parameter on line
6611  */
6612 //================================================================================
6613
6614 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6615                                                      const SMDS_MeshElement* face,
6616                                                      const double            tol,
6617                                                      double &                param)
6618 {
6619   int nbInts = 0;
6620   param = 0;
6621
6622   GeomAPI_ExtremaCurveCurve anExtCC;
6623   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6624   
6625   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6626   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6627   {
6628     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6629                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6630     anExtCC.Init( lineCurve, edge);
6631     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6632     {
6633       Quantity_Parameter pl, pe;
6634       anExtCC.LowerDistanceParameters( pl, pe );
6635       param += pl;
6636       if ( ++nbInts == 2 )
6637         break;
6638     }
6639   }
6640   if ( nbInts > 0 ) param /= nbInts;
6641   return nbInts > 0;
6642 }
6643 //================================================================================
6644 /*!
6645  * \brief Find all faces belonging to the outer boundary of mesh
6646  */
6647 //================================================================================
6648
6649 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6650 {
6651   if ( _outerFacesFound ) return;
6652
6653   // Collect all outer faces by passing from one outer face to another via their links
6654   // and BTW find out if there are internal faces at all.
6655
6656   // checked links and links where outer boundary meets internal one
6657   set< SMESH_TLink > visitedLinks, seamLinks;
6658
6659   // links to treat with already visited faces sharing them
6660   list < TFaceLink > startLinks;
6661
6662   // load startLinks with the first outerFace
6663   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6664   _outerFaces.insert( outerFace );
6665
6666   TIDSortedElemSet emptySet;
6667   while ( !startLinks.empty() )
6668   {
6669     const SMESH_TLink& link  = startLinks.front()._link;
6670     TIDSortedElemSet&  faces = startLinks.front()._faces;
6671
6672     outerFace = *faces.begin();
6673     // find other faces sharing the link
6674     const SMDS_MeshElement* f;
6675     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6676       faces.insert( f );
6677
6678     // select another outer face among the found 
6679     const SMDS_MeshElement* outerFace2 = 0;
6680     if ( faces.size() == 2 )
6681     {
6682       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6683     }
6684     else if ( faces.size() > 2 )
6685     {
6686       seamLinks.insert( link );
6687
6688       // link direction within the outerFace
6689       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6690                    SMESH_TNodeXYZ( link.node2()));
6691       int i1 = outerFace->GetNodeIndex( link.node1() );
6692       int i2 = outerFace->GetNodeIndex( link.node2() );
6693       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6694       if ( rev ) n1n2.Reverse();
6695       // outerFace normal
6696       gp_XYZ ofNorm, fNorm;
6697       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6698       {
6699         // direction from the link inside outerFace
6700         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6701         // sort all other faces by angle with the dirInOF
6702         map< double, const SMDS_MeshElement* > angle2Face;
6703         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6704         for ( ; face != faces.end(); ++face )
6705         {
6706           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6707             continue;
6708           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6709           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6710           if ( angle < 0 ) angle += 2*PI;
6711           angle2Face.insert( make_pair( angle, *face ));
6712         }
6713         if ( !angle2Face.empty() )
6714           outerFace2 = angle2Face.begin()->second;
6715       }
6716     }
6717     // store the found outer face and add its links to continue seaching from
6718     if ( outerFace2 )
6719     {
6720       _outerFaces.insert( outerFace );
6721       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6722       for ( int i = 0; i < nbNodes; ++i )
6723       {
6724         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6725         if ( visitedLinks.insert( link2 ).second )
6726           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6727       }
6728     }
6729     startLinks.pop_front();
6730   }
6731   _outerFacesFound = true;
6732
6733   if ( !seamLinks.empty() )
6734   {
6735     // There are internal boundaries touching the outher one,
6736     // find all faces of internal boundaries in order to find
6737     // faces of boundaries of holes, if any.
6738     
6739   }
6740   else
6741   {
6742     _outerFaces.clear();
6743   }
6744 }
6745
6746 //=======================================================================
6747 /*!
6748  * \brief Find elements of given type where the given point is IN or ON.
6749  *        Returns nb of found elements and elements them-selves.
6750  *
6751  * 'ALL' type means elements of any type excluding nodes and 0D elements
6752  */
6753 //=======================================================================
6754
6755 int SMESH_ElementSearcherImpl::
6756 FindElementsByPoint(const gp_Pnt&                      point,
6757                     SMDSAbs_ElementType                type,
6758                     vector< const SMDS_MeshElement* >& foundElements)
6759 {
6760   foundElements.clear();
6761
6762   double tolerance = getTolerance();
6763
6764   // =================================================================================
6765   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6766   {
6767     if ( !_nodeSearcher )
6768       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6769
6770     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6771     if ( !closeNode ) return foundElements.size();
6772
6773     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6774       return foundElements.size(); // to far from any node
6775
6776     if ( type == SMDSAbs_Node )
6777     {
6778       foundElements.push_back( closeNode );
6779     }
6780     else
6781     {
6782       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6783       while ( elemIt->more() )
6784         foundElements.push_back( elemIt->next() );
6785     }
6786   }
6787   // =================================================================================
6788   else // elements more complex than 0D
6789   {
6790     if ( !_ebbTree || _elementType != type )
6791     {
6792       if ( _ebbTree ) delete _ebbTree;
6793       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6794     }
6795     TIDSortedElemSet suspectElems;
6796     _ebbTree->getElementsNearPoint( point, suspectElems );
6797     TIDSortedElemSet::iterator elem = suspectElems.begin();
6798     for ( ; elem != suspectElems.end(); ++elem )
6799       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6800         foundElements.push_back( *elem );
6801   }
6802   return foundElements.size();
6803 }
6804
6805 //================================================================================
6806 /*!
6807  * \brief Classify the given point in the closed 2D mesh
6808  */
6809 //================================================================================
6810
6811 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6812 {
6813   double tolerance = getTolerance();
6814   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6815   {
6816     if ( _ebbTree ) delete _ebbTree;
6817     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6818   }
6819   // Algo: analyse transition of a line starting at the point through mesh boundary;
6820   // try three lines parallel to axis of the coordinate system and perform rough
6821   // analysis. If solution is not clear perform thorough analysis.
6822
6823   const int nbAxes = 3;
6824   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6825   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6826   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6827   multimap< int, int > nbInt2Axis; // to find the simplest case
6828   for ( int axis = 0; axis < nbAxes; ++axis )
6829   {
6830     gp_Ax1 lineAxis( point, axisDir[axis]);
6831     gp_Lin line    ( lineAxis );
6832
6833     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6834     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6835
6836     // Intersect faces with the line
6837
6838     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6839     TIDSortedElemSet::iterator face = suspectFaces.begin();
6840     for ( ; face != suspectFaces.end(); ++face )
6841     {
6842       // get face plane
6843       gp_XYZ fNorm;
6844       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6845       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6846
6847       // perform intersection
6848       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6849       if ( !intersection.IsDone() )
6850         continue;
6851       if ( intersection.IsInQuadric() )
6852       {
6853         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6854       }
6855       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6856       {
6857         gp_Pnt intersectionPoint = intersection.Point(1);
6858         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6859           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6860       }
6861     }
6862     // Analyse intersections roughly
6863
6864     int nbInter = u2inters.size();
6865     if ( nbInter == 0 )
6866       return TopAbs_OUT; 
6867
6868     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6869     if ( nbInter == 1 ) // not closed mesh
6870       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6871
6872     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6873       return TopAbs_ON;
6874
6875     if ( (f<0) == (l<0) )
6876       return TopAbs_OUT;
6877
6878     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6879     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6880     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6881       return TopAbs_IN;
6882
6883     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6884
6885     if ( _outerFacesFound ) break; // pass to thorough analysis
6886
6887   } // three attempts - loop on CS axes
6888
6889   // Analyse intersections thoroughly.
6890   // We make two loops maximum, on the first one we only exclude touching intersections,
6891   // on the second, if situation is still unclear, we gather and use information on
6892   // position of faces (internal or outer). If faces position is already gathered,
6893   // we make the second loop right away.
6894
6895   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6896   {
6897     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6898     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6899     {
6900       int axis = nb_axis->second;
6901       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6902
6903       gp_Ax1 lineAxis( point, axisDir[axis]);
6904       gp_Lin line    ( lineAxis );
6905
6906       // add tangent intersections to u2inters
6907       double param;
6908       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6909       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6910         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6911           u2inters.insert(make_pair( param, *tgtInt ));
6912       tangentInters[ axis ].clear();
6913
6914       // Count intersections before and after the point excluding touching ones.
6915       // If hasPositionInfo we count intersections of outer boundary only
6916
6917       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6918       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6919       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6920       bool ok = ! u_int1->second._coincides;
6921       while ( ok && u_int1 != u2inters.end() )
6922       {
6923         double u = u_int1->first;
6924         bool touchingInt = false;
6925         if ( ++u_int2 != u2inters.end() )
6926         {
6927           // skip intersections at the same point (if the line passes through edge or node)
6928           int nbSamePnt = 0;
6929           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6930           {
6931             ++nbSamePnt;
6932             ++u_int2;
6933           }
6934
6935           // skip tangent intersections
6936           int nbTgt = 0;
6937           const SMDS_MeshElement* prevFace = u_int1->second._face;
6938           while ( ok && u_int2->second._coincides )
6939           {
6940             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6941               ok = false;
6942             else
6943             {
6944               nbTgt++;
6945               u_int2++;
6946               ok = ( u_int2 != u2inters.end() );
6947             }
6948           }
6949           if ( !ok ) break;
6950
6951           // skip intersections at the same point after tangent intersections
6952           if ( nbTgt > 0 )
6953           {
6954             double u2 = u_int2->first;
6955             ++u_int2;
6956             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6957             {
6958               ++nbSamePnt;
6959               ++u_int2;
6960             }
6961           }
6962           // decide if we skipped a touching intersection
6963           if ( nbSamePnt + nbTgt > 0 )
6964           {
6965             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6966             map< double, TInters >::iterator u_int = u_int1;
6967             for ( ; u_int != u_int2; ++u_int )
6968             {
6969               if ( u_int->second._coincides ) continue;
6970               double dot = u_int->second._faceNorm * line.Direction();
6971               if ( dot > maxDot ) maxDot = dot;
6972               if ( dot < minDot ) minDot = dot;
6973             }
6974             touchingInt = ( minDot*maxDot < 0 );
6975           }
6976         }
6977         if ( !touchingInt )
6978         {
6979           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6980           {
6981             if ( u < 0 )
6982               ++nbIntBeforePoint;
6983             else
6984               ++nbIntAfterPoint;
6985           }
6986           if ( u < f ) f = u;
6987           if ( u > l ) l = u;
6988         }
6989
6990         u_int1 = u_int2; // to next intersection
6991
6992       } // loop on intersections with one line
6993
6994       if ( ok )
6995       {
6996         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6997           return TopAbs_ON;
6998
6999         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
7000           return TopAbs_OUT; 
7001
7002         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
7003           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
7004
7005         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
7006           return TopAbs_IN;
7007
7008         if ( (f<0) == (l<0) )
7009           return TopAbs_OUT;
7010
7011         if ( hasPositionInfo )
7012           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7013       }
7014     } // loop on intersections of the tree lines - thorough analysis
7015
7016     if ( !hasPositionInfo )
7017     {
7018       // gather info on faces position - is face in the outer boundary or not
7019       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7020       findOuterBoundary( u2inters.begin()->second._face );
7021     }
7022
7023   } // two attempts - with and w/o faces position info in the mesh
7024
7025   return TopAbs_UNKNOWN;
7026 }
7027
7028 //=======================================================================
7029 /*!
7030  * \brief Return elements possibly intersecting the line
7031  */
7032 //=======================================================================
7033
7034 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7035                                                      SMDSAbs_ElementType                type,
7036                                                      vector< const SMDS_MeshElement* >& foundElems)
7037 {
7038   if ( !_ebbTree || _elementType != type )
7039   {
7040     if ( _ebbTree ) delete _ebbTree;
7041     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7042   }
7043   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7044   _ebbTree->getElementsNearLine( line, suspectFaces );
7045   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7046 }
7047
7048 //=======================================================================
7049 /*!
7050  * \brief Return SMESH_ElementSearcher
7051  */
7052 //=======================================================================
7053
7054 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7055 {
7056   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7057 }
7058
7059 //=======================================================================
7060 /*!
7061  * \brief Return SMESH_ElementSearcher
7062  */
7063 //=======================================================================
7064
7065 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7066 {
7067   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7068 }
7069
7070 //=======================================================================
7071 /*!
7072  * \brief Return true if the point is IN or ON of the element
7073  */
7074 //=======================================================================
7075
7076 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7077 {
7078   if ( element->GetType() == SMDSAbs_Volume)
7079   {
7080     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7081   }
7082
7083   // get ordered nodes
7084
7085   vector< gp_XYZ > xyz;
7086   vector<const SMDS_MeshNode*> nodeList;
7087
7088   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7089   if ( element->IsQuadratic() ) {
7090     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7091       nodeIt = f->interlacedNodesElemIterator();
7092     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7093       nodeIt = e->interlacedNodesElemIterator();
7094   }
7095   while ( nodeIt->more() )
7096     {
7097       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7098       xyz.push_back( SMESH_TNodeXYZ(node) );
7099       nodeList.push_back(node);
7100     }
7101
7102   int i, nbNodes = element->NbNodes();
7103
7104   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7105   {
7106     // compute face normal
7107     gp_Vec faceNorm(0,0,0);
7108     xyz.push_back( xyz.front() );
7109     nodeList.push_back( nodeList.front() );
7110     for ( i = 0; i < nbNodes; ++i )
7111     {
7112       gp_Vec edge1( xyz[i+1], xyz[i]);
7113       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7114       faceNorm += edge1 ^ edge2;
7115     }
7116     double normSize = faceNorm.Magnitude();
7117     if ( normSize <= tol )
7118     {
7119       // degenerated face: point is out if it is out of all face edges
7120       for ( i = 0; i < nbNodes; ++i )
7121       {
7122         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7123         if ( !isOut( &edge, point, tol ))
7124           return false;
7125       }
7126       return true;
7127     }
7128     faceNorm /= normSize;
7129
7130     // check if the point lays on face plane
7131     gp_Vec n2p( xyz[0], point );
7132     if ( fabs( n2p * faceNorm ) > tol )
7133       return true; // not on face plane
7134
7135     // check if point is out of face boundary:
7136     // define it by closest transition of a ray point->infinity through face boundary
7137     // on the face plane.
7138     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7139     // to find intersections of the ray with the boundary.
7140     gp_Vec ray = n2p;
7141     gp_Vec plnNorm = ray ^ faceNorm;
7142     normSize = plnNorm.Magnitude();
7143     if ( normSize <= tol ) return false; // point coincides with the first node
7144     plnNorm /= normSize;
7145     // for each node of the face, compute its signed distance to the plane
7146     vector<double> dist( nbNodes + 1);
7147     for ( i = 0; i < nbNodes; ++i )
7148     {
7149       gp_Vec n2p( xyz[i], point );
7150       dist[i] = n2p * plnNorm;
7151     }
7152     dist.back() = dist.front();
7153     // find the closest intersection
7154     int    iClosest = -1;
7155     double rClosest, distClosest = 1e100;;
7156     gp_Pnt pClosest;
7157     for ( i = 0; i < nbNodes; ++i )
7158     {
7159       double r;
7160       if ( fabs( dist[i]) < tol )
7161         r = 0.;
7162       else if ( fabs( dist[i+1]) < tol )
7163         r = 1.;
7164       else if ( dist[i] * dist[i+1] < 0 )
7165         r = dist[i] / ( dist[i] - dist[i+1] );
7166       else
7167         continue; // no intersection
7168       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7169       gp_Vec p2int ( point, pInt);
7170       if ( p2int * ray > -tol ) // right half-space
7171       {
7172         double intDist = p2int.SquareMagnitude();
7173         if ( intDist < distClosest )
7174         {
7175           iClosest = i;
7176           rClosest = r;
7177           pClosest = pInt;
7178           distClosest = intDist;
7179         }
7180       }
7181     }
7182     if ( iClosest < 0 )
7183       return true; // no intesections - out
7184
7185     // analyse transition
7186     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7187     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7188     gp_Vec p2int ( point, pClosest );
7189     bool out = (edgeNorm * p2int) < -tol;
7190     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7191       return out;
7192
7193     // ray pass through a face node; analyze transition through an adjacent edge
7194     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7195     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7196     gp_Vec edgeAdjacent( p1, p2 );
7197     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7198     bool out2 = (edgeNorm2 * p2int) < -tol;
7199
7200     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7201     return covexCorner ? (out || out2) : (out && out2);
7202   }
7203   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7204   {
7205     // point is out of edge if it is NOT ON any straight part of edge
7206     // (we consider quadratic edge as being composed of two straight parts)
7207     for ( i = 1; i < nbNodes; ++i )
7208     {
7209       gp_Vec edge( xyz[i-1], xyz[i]);
7210       gp_Vec n1p ( xyz[i-1], point);
7211       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7212       if ( dist > tol )
7213         continue;
7214       gp_Vec n2p( xyz[i], point );
7215       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7216         continue;
7217       return false; // point is ON this part
7218     }
7219     return true;
7220   }
7221   // Node or 0D element -------------------------------------------------------------------------
7222   {
7223     gp_Vec n2p ( xyz[0], point );
7224     return n2p.Magnitude() <= tol;
7225   }
7226   return true;
7227 }
7228
7229 //=======================================================================
7230 //function : SimplifyFace
7231 //purpose  :
7232 //=======================================================================
7233 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7234                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7235                                     vector<int>&                        quantities) const
7236 {
7237   int nbNodes = faceNodes.size();
7238
7239   if (nbNodes < 3)
7240     return 0;
7241
7242   set<const SMDS_MeshNode*> nodeSet;
7243
7244   // get simple seq of nodes
7245   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7246   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7247   int iSimple = 0, nbUnique = 0;
7248
7249   simpleNodes[iSimple++] = faceNodes[0];
7250   nbUnique++;
7251   for (int iCur = 1; iCur < nbNodes; iCur++) {
7252     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7253       simpleNodes[iSimple++] = faceNodes[iCur];
7254       if (nodeSet.insert( faceNodes[iCur] ).second)
7255         nbUnique++;
7256     }
7257   }
7258   int nbSimple = iSimple;
7259   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7260     nbSimple--;
7261     iSimple--;
7262   }
7263
7264   if (nbUnique < 3)
7265     return 0;
7266
7267   // separate loops
7268   int nbNew = 0;
7269   bool foundLoop = (nbSimple > nbUnique);
7270   while (foundLoop) {
7271     foundLoop = false;
7272     set<const SMDS_MeshNode*> loopSet;
7273     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7274       const SMDS_MeshNode* n = simpleNodes[iSimple];
7275       if (!loopSet.insert( n ).second) {
7276         foundLoop = true;
7277
7278         // separate loop
7279         int iC = 0, curLast = iSimple;
7280         for (; iC < curLast; iC++) {
7281           if (simpleNodes[iC] == n) break;
7282         }
7283         int loopLen = curLast - iC;
7284         if (loopLen > 2) {
7285           // create sub-element
7286           nbNew++;
7287           quantities.push_back(loopLen);
7288           for (; iC < curLast; iC++) {
7289             poly_nodes.push_back(simpleNodes[iC]);
7290           }
7291         }
7292         // shift the rest nodes (place from the first loop position)
7293         for (iC = curLast + 1; iC < nbSimple; iC++) {
7294           simpleNodes[iC - loopLen] = simpleNodes[iC];
7295         }
7296         nbSimple -= loopLen;
7297         iSimple -= loopLen;
7298       }
7299     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7300   } // while (foundLoop)
7301
7302   if (iSimple > 2) {
7303     nbNew++;
7304     quantities.push_back(iSimple);
7305     for (int i = 0; i < iSimple; i++)
7306       poly_nodes.push_back(simpleNodes[i]);
7307   }
7308
7309   return nbNew;
7310 }
7311
7312 //=======================================================================
7313 //function : MergeNodes
7314 //purpose  : In each group, the cdr of nodes are substituted by the first one
7315 //           in all elements.
7316 //=======================================================================
7317
7318 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7319 {
7320   MESSAGE("MergeNodes");
7321   myLastCreatedElems.Clear();
7322   myLastCreatedNodes.Clear();
7323
7324   SMESHDS_Mesh* aMesh = GetMeshDS();
7325
7326   TNodeNodeMap nodeNodeMap; // node to replace - new node
7327   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7328   list< int > rmElemIds, rmNodeIds;
7329
7330   // Fill nodeNodeMap and elems
7331
7332   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7333   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7334     list<const SMDS_MeshNode*>& nodes = *grIt;
7335     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7336     const SMDS_MeshNode* nToKeep = *nIt;
7337     //MESSAGE("node to keep " << nToKeep->GetID());
7338     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7339       const SMDS_MeshNode* nToRemove = *nIt;
7340       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7341       if ( nToRemove != nToKeep ) {
7342         //MESSAGE("  node to remove " << nToRemove->GetID());
7343         rmNodeIds.push_back( nToRemove->GetID() );
7344         AddToSameGroups( nToKeep, nToRemove, aMesh );
7345       }
7346
7347       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7348       while ( invElemIt->more() ) {
7349         const SMDS_MeshElement* elem = invElemIt->next();
7350         elems.insert(elem);
7351       }
7352     }
7353   }
7354   // Change element nodes or remove an element
7355
7356   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7357   for ( ; eIt != elems.end(); eIt++ ) {
7358     const SMDS_MeshElement* elem = *eIt;
7359     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7360     int nbNodes = elem->NbNodes();
7361     int aShapeId = FindShape( elem );
7362
7363     set<const SMDS_MeshNode*> nodeSet;
7364     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7365     int iUnique = 0, iCur = 0, nbRepl = 0;
7366     vector<int> iRepl( nbNodes );
7367
7368     // get new seq of nodes
7369     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7370     while ( itN->more() ) {
7371       const SMDS_MeshNode* n =
7372         static_cast<const SMDS_MeshNode*>( itN->next() );
7373
7374       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7375       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7376         n = (*nnIt).second;
7377         // BUG 0020185: begin
7378         {
7379           bool stopRecur = false;
7380           set<const SMDS_MeshNode*> nodesRecur;
7381           nodesRecur.insert(n);
7382           while (!stopRecur) {
7383             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7384             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7385               n = (*nnIt_i).second;
7386               if (!nodesRecur.insert(n).second) {
7387                 // error: recursive dependancy
7388                 stopRecur = true;
7389               }
7390             }
7391             else
7392               stopRecur = true;
7393           }
7394         }
7395         // BUG 0020185: end
7396         iRepl[ nbRepl++ ] = iCur;
7397       }
7398       curNodes[ iCur ] = n;
7399       bool isUnique = nodeSet.insert( n ).second;
7400       if ( isUnique )
7401         uniqueNodes[ iUnique++ ] = n;
7402       iCur++;
7403     }
7404
7405     // Analyse element topology after replacement
7406
7407     bool isOk = true;
7408     int nbUniqueNodes = nodeSet.size();
7409     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7410     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7411       // Polygons and Polyhedral volumes
7412       if (elem->IsPoly()) {
7413
7414         if (elem->GetType() == SMDSAbs_Face) {
7415           // Polygon
7416           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7417           int inode = 0;
7418           for (; inode < nbNodes; inode++) {
7419             face_nodes[inode] = curNodes[inode];
7420           }
7421
7422           vector<const SMDS_MeshNode *> polygons_nodes;
7423           vector<int> quantities;
7424           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7425           if (nbNew > 0) {
7426             inode = 0;
7427             for (int iface = 0; iface < nbNew; iface++) {
7428               int nbNodes = quantities[iface];
7429               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7430               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7431                 poly_nodes[ii] = polygons_nodes[inode];
7432               }
7433               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7434               myLastCreatedElems.Append(newElem);
7435               if (aShapeId)
7436                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7437             }
7438
7439             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7440             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7441             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7442             int quid =0;
7443             if (nbNew > 0) quid = nbNew - 1;
7444             vector<int> newquant(quantities.begin()+quid, quantities.end());
7445             const SMDS_MeshElement* newElem = 0;
7446             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7447             myLastCreatedElems.Append(newElem);
7448             if ( aShapeId && newElem )
7449               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7450             rmElemIds.push_back(elem->GetID());
7451           }
7452           else {
7453             rmElemIds.push_back(elem->GetID());
7454           }
7455
7456         }
7457         else if (elem->GetType() == SMDSAbs_Volume) {
7458           // Polyhedral volume
7459           if (nbUniqueNodes < 4) {
7460             rmElemIds.push_back(elem->GetID());
7461           }
7462           else {
7463             // each face has to be analyzed in order to check volume validity
7464             const SMDS_VtkVolume* aPolyedre =
7465               dynamic_cast<const SMDS_VtkVolume*>( elem );
7466             if (aPolyedre) {
7467               int nbFaces = aPolyedre->NbFaces();
7468
7469               vector<const SMDS_MeshNode *> poly_nodes;
7470               vector<int> quantities;
7471
7472               for (int iface = 1; iface <= nbFaces; iface++) {
7473                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7474                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7475
7476                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7477                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7478                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7479                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7480                     faceNode = (*nnIt).second;
7481                   }
7482                   faceNodes[inode - 1] = faceNode;
7483                 }
7484
7485                 SimplifyFace(faceNodes, poly_nodes, quantities);
7486               }
7487
7488               if (quantities.size() > 3) {
7489                 // to be done: remove coincident faces
7490               }
7491
7492               if (quantities.size() > 3)
7493                 {
7494                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7495                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7496                   const SMDS_MeshElement* newElem = 0;
7497                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7498                   myLastCreatedElems.Append(newElem);
7499                   if ( aShapeId && newElem )
7500                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7501                   rmElemIds.push_back(elem->GetID());
7502                 }
7503             }
7504             else {
7505               rmElemIds.push_back(elem->GetID());
7506             }
7507           }
7508         }
7509         else {
7510         }
7511
7512         continue;
7513       }
7514
7515       // Regular elements
7516       // TODO not all the possible cases are solved. Find something more generic?
7517       switch ( nbNodes ) {
7518       case 2: ///////////////////////////////////// EDGE
7519         isOk = false; break;
7520       case 3: ///////////////////////////////////// TRIANGLE
7521         isOk = false; break;
7522       case 4:
7523         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7524           isOk = false;
7525         else { //////////////////////////////////// QUADRANGLE
7526           if ( nbUniqueNodes < 3 )
7527             isOk = false;
7528           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7529             isOk = false; // opposite nodes stick
7530           //MESSAGE("isOk " << isOk);
7531         }
7532         break;
7533       case 6: ///////////////////////////////////// PENTAHEDRON
7534         if ( nbUniqueNodes == 4 ) {
7535           // ---------------------------------> tetrahedron
7536           if (nbRepl == 3 &&
7537               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7538             // all top nodes stick: reverse a bottom
7539             uniqueNodes[ 0 ] = curNodes [ 1 ];
7540             uniqueNodes[ 1 ] = curNodes [ 0 ];
7541           }
7542           else if (nbRepl == 3 &&
7543                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7544             // all bottom nodes stick: set a top before
7545             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7546             uniqueNodes[ 0 ] = curNodes [ 3 ];
7547             uniqueNodes[ 1 ] = curNodes [ 4 ];
7548             uniqueNodes[ 2 ] = curNodes [ 5 ];
7549           }
7550           else if (nbRepl == 4 &&
7551                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7552             // a lateral face turns into a line: reverse a bottom
7553             uniqueNodes[ 0 ] = curNodes [ 1 ];
7554             uniqueNodes[ 1 ] = curNodes [ 0 ];
7555           }
7556           else
7557             isOk = false;
7558         }
7559         else if ( nbUniqueNodes == 5 ) {
7560           // PENTAHEDRON --------------------> 2 tetrahedrons
7561           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7562             // a bottom node sticks with a linked top one
7563             // 1.
7564             SMDS_MeshElement* newElem =
7565               aMesh->AddVolume(curNodes[ 3 ],
7566                                curNodes[ 4 ],
7567                                curNodes[ 5 ],
7568                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7569             myLastCreatedElems.Append(newElem);
7570             if ( aShapeId )
7571               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7572             // 2. : reverse a bottom
7573             uniqueNodes[ 0 ] = curNodes [ 1 ];
7574             uniqueNodes[ 1 ] = curNodes [ 0 ];
7575             nbUniqueNodes = 4;
7576           }
7577           else
7578             isOk = false;
7579         }
7580         else
7581           isOk = false;
7582         break;
7583       case 8: {
7584         if(elem->IsQuadratic()) { // Quadratic quadrangle
7585           //   1    5    2
7586           //    +---+---+
7587           //    |       |
7588           //    |       |
7589           //   4+       +6
7590           //    |       |
7591           //    |       |
7592           //    +---+---+
7593           //   0    7    3
7594           isOk = false;
7595           if(nbRepl==2) {
7596             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7597           }
7598           if(nbRepl==3) {
7599             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7600             nbUniqueNodes = 6;
7601             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7602               uniqueNodes[0] = curNodes[0];
7603               uniqueNodes[1] = curNodes[2];
7604               uniqueNodes[2] = curNodes[3];
7605               uniqueNodes[3] = curNodes[5];
7606               uniqueNodes[4] = curNodes[6];
7607               uniqueNodes[5] = curNodes[7];
7608               isOk = true;
7609             }
7610             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7611               uniqueNodes[0] = curNodes[0];
7612               uniqueNodes[1] = curNodes[1];
7613               uniqueNodes[2] = curNodes[2];
7614               uniqueNodes[3] = curNodes[4];
7615               uniqueNodes[4] = curNodes[5];
7616               uniqueNodes[5] = curNodes[6];
7617               isOk = true;
7618             }
7619             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7620               uniqueNodes[0] = curNodes[1];
7621               uniqueNodes[1] = curNodes[2];
7622               uniqueNodes[2] = curNodes[3];
7623               uniqueNodes[3] = curNodes[5];
7624               uniqueNodes[4] = curNodes[6];
7625               uniqueNodes[5] = curNodes[0];
7626               isOk = true;
7627             }
7628             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7629               uniqueNodes[0] = curNodes[0];
7630               uniqueNodes[1] = curNodes[1];
7631               uniqueNodes[2] = curNodes[3];
7632               uniqueNodes[3] = curNodes[4];
7633               uniqueNodes[4] = curNodes[6];
7634               uniqueNodes[5] = curNodes[7];
7635               isOk = true;
7636             }
7637             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7638               uniqueNodes[0] = curNodes[0];
7639               uniqueNodes[1] = curNodes[2];
7640               uniqueNodes[2] = curNodes[3];
7641               uniqueNodes[3] = curNodes[1];
7642               uniqueNodes[4] = curNodes[6];
7643               uniqueNodes[5] = curNodes[7];
7644               isOk = true;
7645             }
7646             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7647               uniqueNodes[0] = curNodes[0];
7648               uniqueNodes[1] = curNodes[1];
7649               uniqueNodes[2] = curNodes[2];
7650               uniqueNodes[3] = curNodes[4];
7651               uniqueNodes[4] = curNodes[5];
7652               uniqueNodes[5] = curNodes[7];
7653               isOk = true;
7654             }
7655             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7656               uniqueNodes[0] = curNodes[0];
7657               uniqueNodes[1] = curNodes[1];
7658               uniqueNodes[2] = curNodes[3];
7659               uniqueNodes[3] = curNodes[4];
7660               uniqueNodes[4] = curNodes[2];
7661               uniqueNodes[5] = curNodes[7];
7662               isOk = true;
7663             }
7664             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7665               uniqueNodes[0] = curNodes[0];
7666               uniqueNodes[1] = curNodes[1];
7667               uniqueNodes[2] = curNodes[2];
7668               uniqueNodes[3] = curNodes[4];
7669               uniqueNodes[4] = curNodes[5];
7670               uniqueNodes[5] = curNodes[3];
7671               isOk = true;
7672             }
7673           }
7674           if(nbRepl==4) {
7675             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7676           }
7677           if(nbRepl==5) {
7678             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7679           }
7680           break;
7681         }
7682         //////////////////////////////////// HEXAHEDRON
7683         isOk = false;
7684         SMDS_VolumeTool hexa (elem);
7685         hexa.SetExternalNormal();
7686         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7687           //////////////////////// ---> tetrahedron
7688           for ( int iFace = 0; iFace < 6; iFace++ ) {
7689             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7690             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7691                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7692                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7693               // one face turns into a point ...
7694               int iOppFace = hexa.GetOppFaceIndex( iFace );
7695               ind = hexa.GetFaceNodesIndices( iOppFace );
7696               int nbStick = 0;
7697               iUnique = 2; // reverse a tetrahedron bottom
7698               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7699                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7700                   nbStick++;
7701                 else if ( iUnique >= 0 )
7702                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7703               }
7704               if ( nbStick == 1 ) {
7705                 // ... and the opposite one - into a triangle.
7706                 // set a top node
7707                 ind = hexa.GetFaceNodesIndices( iFace );
7708                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7709                 isOk = true;
7710               }
7711               break;
7712             }
7713           }
7714         }
7715         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7716           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7717           for ( int iFace = 0; iFace < 6; iFace++ ) {
7718             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7719             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7720                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7721                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7722               // one face turns into a point ...
7723               int iOppFace = hexa.GetOppFaceIndex( iFace );
7724               ind = hexa.GetFaceNodesIndices( iOppFace );
7725               int nbStick = 0;
7726               iUnique = 2;  // reverse a tetrahedron 1 bottom
7727               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7728                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7729                   nbStick++;
7730                 else if ( iUnique >= 0 )
7731                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7732               }
7733               if ( nbStick == 0 ) {
7734                 // ... and the opposite one is a quadrangle
7735                 // set a top node
7736                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7737                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7738                 nbUniqueNodes = 4;
7739                 // tetrahedron 2
7740                 SMDS_MeshElement* newElem =
7741                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7742                                    curNodes[ind[ 3 ]],
7743                                    curNodes[ind[ 2 ]],
7744                                    curNodes[indTop[ 0 ]]);
7745                 myLastCreatedElems.Append(newElem);
7746                 if ( aShapeId )
7747                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7748                 isOk = true;
7749               }
7750               break;
7751             }
7752           }
7753         }
7754         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7755           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7756           // find indices of quad and tri faces
7757           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7758           for ( iFace = 0; iFace < 6; iFace++ ) {
7759             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7760             nodeSet.clear();
7761             for ( iCur = 0; iCur < 4; iCur++ )
7762               nodeSet.insert( curNodes[ind[ iCur ]] );
7763             nbUniqueNodes = nodeSet.size();
7764             if ( nbUniqueNodes == 3 )
7765               iTriFace[ nbTri++ ] = iFace;
7766             else if ( nbUniqueNodes == 4 )
7767               iQuadFace[ nbQuad++ ] = iFace;
7768           }
7769           if (nbQuad == 2 && nbTri == 4 &&
7770               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7771             // 2 opposite quadrangles stuck with a diagonal;
7772             // sample groups of merged indices: (0-4)(2-6)
7773             // --------------------------------------------> 2 tetrahedrons
7774             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7775             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7776             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7777             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7778                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7779               // stuck with 0-2 diagonal
7780               i0  = ind1[ 3 ];
7781               i1d = ind1[ 0 ];
7782               i2  = ind1[ 1 ];
7783               i3d = ind1[ 2 ];
7784               i0t = ind2[ 1 ];
7785               i2t = ind2[ 3 ];
7786             }
7787             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7788                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7789               // stuck with 1-3 diagonal
7790               i0  = ind1[ 0 ];
7791               i1d = ind1[ 1 ];
7792               i2  = ind1[ 2 ];
7793               i3d = ind1[ 3 ];
7794               i0t = ind2[ 0 ];
7795               i2t = ind2[ 1 ];
7796             }
7797             else {
7798               ASSERT(0);
7799             }
7800             // tetrahedron 1
7801             uniqueNodes[ 0 ] = curNodes [ i0 ];
7802             uniqueNodes[ 1 ] = curNodes [ i1d ];
7803             uniqueNodes[ 2 ] = curNodes [ i3d ];
7804             uniqueNodes[ 3 ] = curNodes [ i0t ];
7805             nbUniqueNodes = 4;
7806             // tetrahedron 2
7807             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7808                                                          curNodes[ i2 ],
7809                                                          curNodes[ i3d ],
7810                                                          curNodes[ i2t ]);
7811             myLastCreatedElems.Append(newElem);
7812             if ( aShapeId )
7813               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7814             isOk = true;
7815           }
7816           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7817                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7818             // --------------------------------------------> prism
7819             // find 2 opposite triangles
7820             nbUniqueNodes = 6;
7821             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7822               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7823                 // find indices of kept and replaced nodes
7824                 // and fill unique nodes of 2 opposite triangles
7825                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7826                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7827                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7828                 // fill unique nodes
7829                 iUnique = 0;
7830                 isOk = true;
7831                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7832                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7833                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7834                   if ( n == nInit ) {
7835                     // iCur of a linked node of the opposite face (make normals co-directed):
7836                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7837                     // check that correspondent corners of triangles are linked
7838                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7839                       isOk = false;
7840                     else {
7841                       uniqueNodes[ iUnique ] = n;
7842                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7843                       iUnique++;
7844                     }
7845                   }
7846                 }
7847                 break;
7848               }
7849             }
7850           }
7851         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7852         break;
7853       } // HEXAHEDRON
7854
7855       default:
7856         isOk = false;
7857       } // switch ( nbNodes )
7858
7859     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7860
7861     if ( isOk ) {
7862       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7863         // Change nodes of polyedre
7864         const SMDS_VtkVolume* aPolyedre =
7865           dynamic_cast<const SMDS_VtkVolume*>( elem );
7866         if (aPolyedre) {
7867           int nbFaces = aPolyedre->NbFaces();
7868
7869           vector<const SMDS_MeshNode *> poly_nodes;
7870           vector<int> quantities (nbFaces);
7871
7872           for (int iface = 1; iface <= nbFaces; iface++) {
7873             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7874             quantities[iface - 1] = nbFaceNodes;
7875
7876             for (inode = 1; inode <= nbFaceNodes; inode++) {
7877               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7878
7879               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7880               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7881                 curNode = (*nnIt).second;
7882               }
7883               poly_nodes.push_back(curNode);
7884             }
7885           }
7886           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7887         }
7888       }
7889       else {
7890         //int elemId = elem->GetID();
7891         //MESSAGE("Change regular element or polygon " << elemId);
7892         SMDSAbs_ElementType etyp = elem->GetType();
7893         uniqueNodes.resize(nbUniqueNodes);
7894         SMDS_MeshElement* newElem = 0;
7895         if (elem->GetEntityType() == SMDSEntity_Polygon)
7896           newElem = this->AddElement(uniqueNodes, etyp, true);
7897         else
7898           newElem = this->AddElement(uniqueNodes, etyp, false);
7899         if (newElem)
7900           {
7901             myLastCreatedElems.Append(newElem);
7902             if ( aShapeId )
7903               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7904           }
7905         aMesh->RemoveElement(elem);
7906       }
7907     }
7908     else {
7909       // Remove invalid regular element or invalid polygon
7910       //MESSAGE("Remove invalid " << elem->GetID());
7911       rmElemIds.push_back( elem->GetID() );
7912     }
7913
7914   } // loop on elements
7915
7916   // Remove bad elements, then equal nodes (order important)
7917
7918   Remove( rmElemIds, false );
7919   Remove( rmNodeIds, true );
7920
7921 }
7922
7923
7924 // ========================================================
7925 // class   : SortableElement
7926 // purpose : allow sorting elements basing on their nodes
7927 // ========================================================
7928 class SortableElement : public set <const SMDS_MeshElement*>
7929 {
7930 public:
7931
7932   SortableElement( const SMDS_MeshElement* theElem )
7933   {
7934     myElem = theElem;
7935     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7936     while ( nodeIt->more() )
7937       this->insert( nodeIt->next() );
7938   }
7939
7940   const SMDS_MeshElement* Get() const
7941   { return myElem; }
7942
7943   void Set(const SMDS_MeshElement* e) const
7944   { myElem = e; }
7945
7946
7947 private:
7948   mutable const SMDS_MeshElement* myElem;
7949 };
7950
7951 //=======================================================================
7952 //function : FindEqualElements
7953 //purpose  : Return list of group of elements built on the same nodes.
7954 //           Search among theElements or in the whole mesh if theElements is empty
7955 //=======================================================================
7956 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7957                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7958 {
7959   myLastCreatedElems.Clear();
7960   myLastCreatedNodes.Clear();
7961
7962   typedef set<const SMDS_MeshElement*> TElemsSet;
7963   typedef map< SortableElement, int > TMapOfNodeSet;
7964   typedef list<int> TGroupOfElems;
7965
7966   TElemsSet elems;
7967   if ( theElements.empty() )
7968   { // get all elements in the mesh
7969     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7970     while ( eIt->more() )
7971       elems.insert( elems.end(), eIt->next());
7972   }
7973   else
7974     elems = theElements;
7975
7976   vector< TGroupOfElems > arrayOfGroups;
7977   TGroupOfElems groupOfElems;
7978   TMapOfNodeSet mapOfNodeSet;
7979
7980   TElemsSet::iterator elemIt = elems.begin();
7981   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7982     const SMDS_MeshElement* curElem = *elemIt;
7983     SortableElement SE(curElem);
7984     int ind = -1;
7985     // check uniqueness
7986     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7987     if( !(pp.second) ) {
7988       TMapOfNodeSet::iterator& itSE = pp.first;
7989       ind = (*itSE).second;
7990       arrayOfGroups[ind].push_back(curElem->GetID());
7991     }
7992     else {
7993       groupOfElems.clear();
7994       groupOfElems.push_back(curElem->GetID());
7995       arrayOfGroups.push_back(groupOfElems);
7996       i++;
7997     }
7998   }
7999
8000   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
8001   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8002     groupOfElems = *groupIt;
8003     if ( groupOfElems.size() > 1 ) {
8004       groupOfElems.sort();
8005       theGroupsOfElementsID.push_back(groupOfElems);
8006     }
8007   }
8008 }
8009
8010 //=======================================================================
8011 //function : MergeElements
8012 //purpose  : In each given group, substitute all elements by the first one.
8013 //=======================================================================
8014
8015 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8016 {
8017   myLastCreatedElems.Clear();
8018   myLastCreatedNodes.Clear();
8019
8020   typedef list<int> TListOfIDs;
8021   TListOfIDs rmElemIds; // IDs of elems to remove
8022
8023   SMESHDS_Mesh* aMesh = GetMeshDS();
8024
8025   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8026   while ( groupsIt != theGroupsOfElementsID.end() ) {
8027     TListOfIDs& aGroupOfElemID = *groupsIt;
8028     aGroupOfElemID.sort();
8029     int elemIDToKeep = aGroupOfElemID.front();
8030     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8031     aGroupOfElemID.pop_front();
8032     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8033     while ( idIt != aGroupOfElemID.end() ) {
8034       int elemIDToRemove = *idIt;
8035       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8036       // add the kept element in groups of removed one (PAL15188)
8037       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8038       rmElemIds.push_back( elemIDToRemove );
8039       ++idIt;
8040     }
8041     ++groupsIt;
8042   }
8043
8044   Remove( rmElemIds, false );
8045 }
8046
8047 //=======================================================================
8048 //function : MergeEqualElements
8049 //purpose  : Remove all but one of elements built on the same nodes.
8050 //=======================================================================
8051
8052 void SMESH_MeshEditor::MergeEqualElements()
8053 {
8054   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8055                                                  to merge equal elements in the whole mesh */
8056   TListOfListOfElementsID aGroupsOfElementsID;
8057   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8058   MergeElements(aGroupsOfElementsID);
8059 }
8060
8061 //=======================================================================
8062 //function : FindFaceInSet
8063 //purpose  : Return a face having linked nodes n1 and n2 and which is
8064 //           - not in avoidSet,
8065 //           - in elemSet provided that !elemSet.empty()
8066 //           i1 and i2 optionally returns indices of n1 and n2
8067 //=======================================================================
8068
8069 const SMDS_MeshElement*
8070 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8071                                 const SMDS_MeshNode*    n2,
8072                                 const TIDSortedElemSet& elemSet,
8073                                 const TIDSortedElemSet& avoidSet,
8074                                 int*                    n1ind,
8075                                 int*                    n2ind)
8076
8077 {
8078   int i1, i2;
8079   const SMDS_MeshElement* face = 0;
8080
8081   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8082   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8083   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8084   {
8085     //MESSAGE("in while ( invElemIt->more() && !face )");
8086     const SMDS_MeshElement* elem = invElemIt->next();
8087     if (avoidSet.count( elem ))
8088       continue;
8089     if ( !elemSet.empty() && !elemSet.count( elem ))
8090       continue;
8091     // index of n1
8092     i1 = elem->GetNodeIndex( n1 );
8093     // find a n2 linked to n1
8094     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8095     for ( int di = -1; di < 2 && !face; di += 2 )
8096     {
8097       i2 = (i1+di+nbN) % nbN;
8098       if ( elem->GetNode( i2 ) == n2 )
8099         face = elem;
8100     }
8101     if ( !face && elem->IsQuadratic())
8102     {
8103       // analysis for quadratic elements using all nodes
8104       const SMDS_VtkFace* F =
8105         dynamic_cast<const SMDS_VtkFace*>(elem);
8106       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8107       // use special nodes iterator
8108       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8109       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8110       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8111       {
8112         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8113         if ( n1 == prevN && n2 == n )
8114         {
8115           face = elem;
8116         }
8117         else if ( n2 == prevN && n1 == n )
8118         {
8119           face = elem; swap( i1, i2 );
8120         }
8121         prevN = n;
8122       }
8123     }
8124   }
8125   if ( n1ind ) *n1ind = i1;
8126   if ( n2ind ) *n2ind = i2;
8127   return face;
8128 }
8129
8130 //=======================================================================
8131 //function : findAdjacentFace
8132 //purpose  :
8133 //=======================================================================
8134
8135 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8136                                                 const SMDS_MeshNode* n2,
8137                                                 const SMDS_MeshElement* elem)
8138 {
8139   TIDSortedElemSet elemSet, avoidSet;
8140   if ( elem )
8141     avoidSet.insert ( elem );
8142   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8143 }
8144
8145 //=======================================================================
8146 //function : FindFreeBorder
8147 //purpose  :
8148 //=======================================================================
8149
8150 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8151
8152 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8153                                        const SMDS_MeshNode*             theSecondNode,
8154                                        const SMDS_MeshNode*             theLastNode,
8155                                        list< const SMDS_MeshNode* > &   theNodes,
8156                                        list< const SMDS_MeshElement* >& theFaces)
8157 {
8158   if ( !theFirstNode || !theSecondNode )
8159     return false;
8160   // find border face between theFirstNode and theSecondNode
8161   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8162   if ( !curElem )
8163     return false;
8164
8165   theFaces.push_back( curElem );
8166   theNodes.push_back( theFirstNode );
8167   theNodes.push_back( theSecondNode );
8168
8169   //vector<const SMDS_MeshNode*> nodes;
8170   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8171   TIDSortedElemSet foundElems;
8172   bool needTheLast = ( theLastNode != 0 );
8173
8174   while ( nStart != theLastNode ) {
8175     if ( nStart == theFirstNode )
8176       return !needTheLast;
8177
8178     // find all free border faces sharing form nStart
8179
8180     list< const SMDS_MeshElement* > curElemList;
8181     list< const SMDS_MeshNode* > nStartList;
8182     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8183     while ( invElemIt->more() ) {
8184       const SMDS_MeshElement* e = invElemIt->next();
8185       if ( e == curElem || foundElems.insert( e ).second ) {
8186         // get nodes
8187         int iNode = 0, nbNodes = e->NbNodes();
8188         //const SMDS_MeshNode* nodes[nbNodes+1];
8189         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8190
8191         if(e->IsQuadratic()) {
8192           const SMDS_VtkFace* F =
8193             dynamic_cast<const SMDS_VtkFace*>(e);
8194           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8195           // use special nodes iterator
8196           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8197           while( anIter->more() ) {
8198             nodes[ iNode++ ] = cast2Node(anIter->next());
8199           }
8200         }
8201         else {
8202           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8203           while ( nIt->more() )
8204             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8205         }
8206         nodes[ iNode ] = nodes[ 0 ];
8207         // check 2 links
8208         for ( iNode = 0; iNode < nbNodes; iNode++ )
8209           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8210                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8211               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8212           {
8213             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8214             curElemList.push_back( e );
8215           }
8216       }
8217     }
8218     // analyse the found
8219
8220     int nbNewBorders = curElemList.size();
8221     if ( nbNewBorders == 0 ) {
8222       // no free border furthermore
8223       return !needTheLast;
8224     }
8225     else if ( nbNewBorders == 1 ) {
8226       // one more element found
8227       nIgnore = nStart;
8228       nStart = nStartList.front();
8229       curElem = curElemList.front();
8230       theFaces.push_back( curElem );
8231       theNodes.push_back( nStart );
8232     }
8233     else {
8234       // several continuations found
8235       list< const SMDS_MeshElement* >::iterator curElemIt;
8236       list< const SMDS_MeshNode* >::iterator nStartIt;
8237       // check if one of them reached the last node
8238       if ( needTheLast ) {
8239         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8240              curElemIt!= curElemList.end();
8241              curElemIt++, nStartIt++ )
8242           if ( *nStartIt == theLastNode ) {
8243             theFaces.push_back( *curElemIt );
8244             theNodes.push_back( *nStartIt );
8245             return true;
8246           }
8247       }
8248       // find the best free border by the continuations
8249       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8250       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8251       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8252            curElemIt!= curElemList.end();
8253            curElemIt++, nStartIt++ )
8254       {
8255         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8256         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8257         // find one more free border
8258         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8259           cNL->clear();
8260           cFL->clear();
8261         }
8262         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8263           // choice: clear a worse one
8264           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8265           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8266           contNodes[ iWorse ].clear();
8267           contFaces[ iWorse ].clear();
8268         }
8269       }
8270       if ( contNodes[0].empty() && contNodes[1].empty() )
8271         return false;
8272
8273       // append the best free border
8274       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8275       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8276       theNodes.pop_back(); // remove nIgnore
8277       theNodes.pop_back(); // remove nStart
8278       theFaces.pop_back(); // remove curElem
8279       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8280       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8281       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8282       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8283       return true;
8284
8285     } // several continuations found
8286   } // while ( nStart != theLastNode )
8287
8288   return true;
8289 }
8290
8291 //=======================================================================
8292 //function : CheckFreeBorderNodes
8293 //purpose  : Return true if the tree nodes are on a free border
8294 //=======================================================================
8295
8296 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8297                                             const SMDS_MeshNode* theNode2,
8298                                             const SMDS_MeshNode* theNode3)
8299 {
8300   list< const SMDS_MeshNode* > nodes;
8301   list< const SMDS_MeshElement* > faces;
8302   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8303 }
8304
8305 //=======================================================================
8306 //function : SewFreeBorder
8307 //purpose  :
8308 //=======================================================================
8309
8310 SMESH_MeshEditor::Sew_Error
8311 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8312                                  const SMDS_MeshNode* theBordSecondNode,
8313                                  const SMDS_MeshNode* theBordLastNode,
8314                                  const SMDS_MeshNode* theSideFirstNode,
8315                                  const SMDS_MeshNode* theSideSecondNode,
8316                                  const SMDS_MeshNode* theSideThirdNode,
8317                                  const bool           theSideIsFreeBorder,
8318                                  const bool           toCreatePolygons,
8319                                  const bool           toCreatePolyedrs)
8320 {
8321   myLastCreatedElems.Clear();
8322   myLastCreatedNodes.Clear();
8323
8324   MESSAGE("::SewFreeBorder()");
8325   Sew_Error aResult = SEW_OK;
8326
8327   // ====================================
8328   //    find side nodes and elements
8329   // ====================================
8330
8331   list< const SMDS_MeshNode* > nSide[ 2 ];
8332   list< const SMDS_MeshElement* > eSide[ 2 ];
8333   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8334   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8335
8336   // Free border 1
8337   // --------------
8338   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8339                       nSide[0], eSide[0])) {
8340     MESSAGE(" Free Border 1 not found " );
8341     aResult = SEW_BORDER1_NOT_FOUND;
8342   }
8343   if (theSideIsFreeBorder) {
8344     // Free border 2
8345     // --------------
8346     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8347                         nSide[1], eSide[1])) {
8348       MESSAGE(" Free Border 2 not found " );
8349       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8350     }
8351   }
8352   if ( aResult != SEW_OK )
8353     return aResult;
8354
8355   if (!theSideIsFreeBorder) {
8356     // Side 2
8357     // --------------
8358
8359     // -------------------------------------------------------------------------
8360     // Algo:
8361     // 1. If nodes to merge are not coincident, move nodes of the free border
8362     //    from the coord sys defined by the direction from the first to last
8363     //    nodes of the border to the correspondent sys of the side 2
8364     // 2. On the side 2, find the links most co-directed with the correspondent
8365     //    links of the free border
8366     // -------------------------------------------------------------------------
8367
8368     // 1. Since sewing may break if there are volumes to split on the side 2,
8369     //    we wont move nodes but just compute new coordinates for them
8370     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8371     TNodeXYZMap nBordXYZ;
8372     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8373     list< const SMDS_MeshNode* >::iterator nBordIt;
8374
8375     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8376     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8377     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8378     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8379     double tol2 = 1.e-8;
8380     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8381     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8382       // Need node movement.
8383
8384       // find X and Z axes to create trsf
8385       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8386       gp_Vec X = Zs ^ Zb;
8387       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8388         // Zb || Zs
8389         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8390
8391       // coord systems
8392       gp_Ax3 toBordAx( Pb1, Zb, X );
8393       gp_Ax3 fromSideAx( Ps1, Zs, X );
8394       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8395       // set trsf
8396       gp_Trsf toBordSys, fromSide2Sys;
8397       toBordSys.SetTransformation( toBordAx );
8398       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8399       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8400
8401       // move
8402       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8403         const SMDS_MeshNode* n = *nBordIt;
8404         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8405         toBordSys.Transforms( xyz );
8406         fromSide2Sys.Transforms( xyz );
8407         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8408       }
8409     }
8410     else {
8411       // just insert nodes XYZ in the nBordXYZ map
8412       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8413         const SMDS_MeshNode* n = *nBordIt;
8414         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8415       }
8416     }
8417
8418     // 2. On the side 2, find the links most co-directed with the correspondent
8419     //    links of the free border
8420
8421     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8422     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8423     sideNodes.push_back( theSideFirstNode );
8424
8425     bool hasVolumes = false;
8426     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8427     set<long> foundSideLinkIDs, checkedLinkIDs;
8428     SMDS_VolumeTool volume;
8429     //const SMDS_MeshNode* faceNodes[ 4 ];
8430
8431     const SMDS_MeshNode*    sideNode;
8432     const SMDS_MeshElement* sideElem;
8433     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8434     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8435     nBordIt = bordNodes.begin();
8436     nBordIt++;
8437     // border node position and border link direction to compare with
8438     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8439     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8440     // choose next side node by link direction or by closeness to
8441     // the current border node:
8442     bool searchByDir = ( *nBordIt != theBordLastNode );
8443     do {
8444       // find the next node on the Side 2
8445       sideNode = 0;
8446       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8447       long linkID;
8448       checkedLinkIDs.clear();
8449       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8450
8451       // loop on inverse elements of current node (prevSideNode) on the Side 2
8452       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8453       while ( invElemIt->more() )
8454       {
8455         const SMDS_MeshElement* elem = invElemIt->next();
8456         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8457         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8458         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8459         bool isVolume = volume.Set( elem );
8460         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8461         if ( isVolume ) // --volume
8462           hasVolumes = true;
8463         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8464           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8465           if(elem->IsQuadratic()) {
8466             const SMDS_VtkFace* F =
8467               dynamic_cast<const SMDS_VtkFace*>(elem);
8468             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8469             // use special nodes iterator
8470             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8471             while( anIter->more() ) {
8472               nodes[ iNode ] = cast2Node(anIter->next());
8473               if ( nodes[ iNode++ ] == prevSideNode )
8474                 iPrevNode = iNode - 1;
8475             }
8476           }
8477           else {
8478             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8479             while ( nIt->more() ) {
8480               nodes[ iNode ] = cast2Node( nIt->next() );
8481               if ( nodes[ iNode++ ] == prevSideNode )
8482                 iPrevNode = iNode - 1;
8483             }
8484           }
8485           // there are 2 links to check
8486           nbNodes = 2;
8487         }
8488         else // --edge
8489           continue;
8490         // loop on links, to be precise, on the second node of links
8491         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8492           const SMDS_MeshNode* n = nodes[ iNode ];
8493           if ( isVolume ) {
8494             if ( !volume.IsLinked( n, prevSideNode ))
8495               continue;
8496           }
8497           else {
8498             if ( iNode ) // a node before prevSideNode
8499               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8500             else         // a node after prevSideNode
8501               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8502           }
8503           // check if this link was already used
8504           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8505           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8506           if (!isJustChecked &&
8507               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8508           {
8509             // test a link geometrically
8510             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8511             bool linkIsBetter = false;
8512             double dot = 0.0, dist = 0.0;
8513             if ( searchByDir ) { // choose most co-directed link
8514               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8515               linkIsBetter = ( dot > maxDot );
8516             }
8517             else { // choose link with the node closest to bordPos
8518               dist = ( nextXYZ - bordPos ).SquareModulus();
8519               linkIsBetter = ( dist < minDist );
8520             }
8521             if ( linkIsBetter ) {
8522               maxDot = dot;
8523               minDist = dist;
8524               linkID = iLink;
8525               sideNode = n;
8526               sideElem = elem;
8527             }
8528           }
8529         }
8530       } // loop on inverse elements of prevSideNode
8531
8532       if ( !sideNode ) {
8533         MESSAGE(" Cant find path by links of the Side 2 ");
8534         return SEW_BAD_SIDE_NODES;
8535       }
8536       sideNodes.push_back( sideNode );
8537       sideElems.push_back( sideElem );
8538       foundSideLinkIDs.insert ( linkID );
8539       prevSideNode = sideNode;
8540
8541       if ( *nBordIt == theBordLastNode )
8542         searchByDir = false;
8543       else {
8544         // find the next border link to compare with
8545         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8546         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8547         // move to next border node if sideNode is before forward border node (bordPos)
8548         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8549           prevBordNode = *nBordIt;
8550           nBordIt++;
8551           bordPos = nBordXYZ[ *nBordIt ];
8552           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8553           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8554         }
8555       }
8556     }
8557     while ( sideNode != theSideSecondNode );
8558
8559     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8560       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8561       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8562     }
8563   } // end nodes search on the side 2
8564
8565   // ============================
8566   // sew the border to the side 2
8567   // ============================
8568
8569   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8570   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8571
8572   TListOfListOfNodes nodeGroupsToMerge;
8573   if ( nbNodes[0] == nbNodes[1] ||
8574        ( theSideIsFreeBorder && !theSideThirdNode)) {
8575
8576     // all nodes are to be merged
8577
8578     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8579          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8580          nIt[0]++, nIt[1]++ )
8581     {
8582       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8583       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8584       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8585     }
8586   }
8587   else {
8588
8589     // insert new nodes into the border and the side to get equal nb of segments
8590
8591     // get normalized parameters of nodes on the borders
8592     //double param[ 2 ][ maxNbNodes ];
8593     double* param[ 2 ];
8594     param[0] = new double [ maxNbNodes ];
8595     param[1] = new double [ maxNbNodes ];
8596     int iNode, iBord;
8597     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8598       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8599       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8600       const SMDS_MeshNode* nPrev = *nIt;
8601       double bordLength = 0;
8602       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8603         const SMDS_MeshNode* nCur = *nIt;
8604         gp_XYZ segment (nCur->X() - nPrev->X(),
8605                         nCur->Y() - nPrev->Y(),
8606                         nCur->Z() - nPrev->Z());
8607         double segmentLen = segment.Modulus();
8608         bordLength += segmentLen;
8609         param[ iBord ][ iNode ] = bordLength;
8610         nPrev = nCur;
8611       }
8612       // normalize within [0,1]
8613       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8614         param[ iBord ][ iNode ] /= bordLength;
8615       }
8616     }
8617
8618     // loop on border segments
8619     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8620     int i[ 2 ] = { 0, 0 };
8621     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8622     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8623
8624     TElemOfNodeListMap insertMap;
8625     TElemOfNodeListMap::iterator insertMapIt;
8626     // insertMap is
8627     // key:   elem to insert nodes into
8628     // value: 2 nodes to insert between + nodes to be inserted
8629     do {
8630       bool next[ 2 ] = { false, false };
8631
8632       // find min adjacent segment length after sewing
8633       double nextParam = 10., prevParam = 0;
8634       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8635         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8636           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8637         if ( i[ iBord ] > 0 )
8638           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8639       }
8640       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8641       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8642       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8643
8644       // choose to insert or to merge nodes
8645       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8646       if ( Abs( du ) <= minSegLen * 0.2 ) {
8647         // merge
8648         // ------
8649         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8650         const SMDS_MeshNode* n0 = *nIt[0];
8651         const SMDS_MeshNode* n1 = *nIt[1];
8652         nodeGroupsToMerge.back().push_back( n1 );
8653         nodeGroupsToMerge.back().push_back( n0 );
8654         // position of node of the border changes due to merge
8655         param[ 0 ][ i[0] ] += du;
8656         // move n1 for the sake of elem shape evaluation during insertion.
8657         // n1 will be removed by MergeNodes() anyway
8658         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8659         next[0] = next[1] = true;
8660       }
8661       else {
8662         // insert
8663         // ------
8664         int intoBord = ( du < 0 ) ? 0 : 1;
8665         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8666         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8667         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8668         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8669         if ( intoBord == 1 ) {
8670           // move node of the border to be on a link of elem of the side
8671           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8672           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8673           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8674           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8675           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8676         }
8677         insertMapIt = insertMap.find( elem );
8678         bool notFound = ( insertMapIt == insertMap.end() );
8679         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8680         if ( otherLink ) {
8681           // insert into another link of the same element:
8682           // 1. perform insertion into the other link of the elem
8683           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8684           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8685           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8686           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8687           // 2. perform insertion into the link of adjacent faces
8688           while (true) {
8689             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8690             if ( adjElem )
8691               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8692             else
8693               break;
8694           }
8695           if (toCreatePolyedrs) {
8696             // perform insertion into the links of adjacent volumes
8697             UpdateVolumes(n12, n22, nodeList);
8698           }
8699           // 3. find an element appeared on n1 and n2 after the insertion
8700           insertMap.erase( elem );
8701           elem = findAdjacentFace( n1, n2, 0 );
8702         }
8703         if ( notFound || otherLink ) {
8704           // add element and nodes of the side into the insertMap
8705           insertMapIt = insertMap.insert
8706             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8707           (*insertMapIt).second.push_back( n1 );
8708           (*insertMapIt).second.push_back( n2 );
8709         }
8710         // add node to be inserted into elem
8711         (*insertMapIt).second.push_back( nIns );
8712         next[ 1 - intoBord ] = true;
8713       }
8714
8715       // go to the next segment
8716       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8717         if ( next[ iBord ] ) {
8718           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8719             eIt[ iBord ]++;
8720           nPrev[ iBord ] = *nIt[ iBord ];
8721           nIt[ iBord ]++; i[ iBord ]++;
8722         }
8723       }
8724     }
8725     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8726
8727     // perform insertion of nodes into elements
8728
8729     for (insertMapIt = insertMap.begin();
8730          insertMapIt != insertMap.end();
8731          insertMapIt++ )
8732     {
8733       const SMDS_MeshElement* elem = (*insertMapIt).first;
8734       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8735       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8736       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8737
8738       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8739
8740       if ( !theSideIsFreeBorder ) {
8741         // look for and insert nodes into the faces adjacent to elem
8742         while (true) {
8743           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8744           if ( adjElem )
8745             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8746           else
8747             break;
8748         }
8749       }
8750       if (toCreatePolyedrs) {
8751         // perform insertion into the links of adjacent volumes
8752         UpdateVolumes(n1, n2, nodeList);
8753       }
8754     }
8755
8756     delete param[0];
8757     delete param[1];
8758   } // end: insert new nodes
8759
8760   MergeNodes ( nodeGroupsToMerge );
8761
8762   return aResult;
8763 }
8764
8765 //=======================================================================
8766 //function : InsertNodesIntoLink
8767 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8768 //           and theBetweenNode2 and split theElement
8769 //=======================================================================
8770
8771 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8772                                            const SMDS_MeshNode*        theBetweenNode1,
8773                                            const SMDS_MeshNode*        theBetweenNode2,
8774                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8775                                            const bool                  toCreatePoly)
8776 {
8777   if ( theFace->GetType() != SMDSAbs_Face ) return;
8778
8779   // find indices of 2 link nodes and of the rest nodes
8780   int iNode = 0, il1, il2, i3, i4;
8781   il1 = il2 = i3 = i4 = -1;
8782   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8783   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8784
8785   if(theFace->IsQuadratic()) {
8786     const SMDS_VtkFace* F =
8787       dynamic_cast<const SMDS_VtkFace*>(theFace);
8788     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8789     // use special nodes iterator
8790     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8791     while( anIter->more() ) {
8792       const SMDS_MeshNode* n = cast2Node(anIter->next());
8793       if ( n == theBetweenNode1 )
8794         il1 = iNode;
8795       else if ( n == theBetweenNode2 )
8796         il2 = iNode;
8797       else if ( i3 < 0 )
8798         i3 = iNode;
8799       else
8800         i4 = iNode;
8801       nodes[ iNode++ ] = n;
8802     }
8803   }
8804   else {
8805     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8806     while ( nodeIt->more() ) {
8807       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8808       if ( n == theBetweenNode1 )
8809         il1 = iNode;
8810       else if ( n == theBetweenNode2 )
8811         il2 = iNode;
8812       else if ( i3 < 0 )
8813         i3 = iNode;
8814       else
8815         i4 = iNode;
8816       nodes[ iNode++ ] = n;
8817     }
8818   }
8819   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8820     return ;
8821
8822   // arrange link nodes to go one after another regarding the face orientation
8823   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8824   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8825   if ( reverse ) {
8826     iNode = il1;
8827     il1 = il2;
8828     il2 = iNode;
8829     aNodesToInsert.reverse();
8830   }
8831   // check that not link nodes of a quadrangles are in good order
8832   int nbFaceNodes = theFace->NbNodes();
8833   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8834     iNode = i3;
8835     i3 = i4;
8836     i4 = iNode;
8837   }
8838
8839   if (toCreatePoly || theFace->IsPoly()) {
8840
8841     iNode = 0;
8842     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8843
8844     // add nodes of face up to first node of link
8845     bool isFLN = false;
8846
8847     if(theFace->IsQuadratic()) {
8848       const SMDS_VtkFace* F =
8849         dynamic_cast<const SMDS_VtkFace*>(theFace);
8850       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8851       // use special nodes iterator
8852       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8853       while( anIter->more()  && !isFLN ) {
8854         const SMDS_MeshNode* n = cast2Node(anIter->next());
8855         poly_nodes[iNode++] = n;
8856         if (n == nodes[il1]) {
8857           isFLN = true;
8858         }
8859       }
8860       // add nodes to insert
8861       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8862       for (; nIt != aNodesToInsert.end(); nIt++) {
8863         poly_nodes[iNode++] = *nIt;
8864       }
8865       // add nodes of face starting from last node of link
8866       while ( anIter->more() ) {
8867         poly_nodes[iNode++] = cast2Node(anIter->next());
8868       }
8869     }
8870     else {
8871       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8872       while ( nodeIt->more() && !isFLN ) {
8873         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8874         poly_nodes[iNode++] = n;
8875         if (n == nodes[il1]) {
8876           isFLN = true;
8877         }
8878       }
8879       // add nodes to insert
8880       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8881       for (; nIt != aNodesToInsert.end(); nIt++) {
8882         poly_nodes[iNode++] = *nIt;
8883       }
8884       // add nodes of face starting from last node of link
8885       while ( nodeIt->more() ) {
8886         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8887         poly_nodes[iNode++] = n;
8888       }
8889     }
8890
8891     // edit or replace the face
8892     SMESHDS_Mesh *aMesh = GetMeshDS();
8893
8894     if (theFace->IsPoly()) {
8895       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8896     }
8897     else {
8898       int aShapeId = FindShape( theFace );
8899
8900       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8901       myLastCreatedElems.Append(newElem);
8902       if ( aShapeId && newElem )
8903         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8904
8905       aMesh->RemoveElement(theFace);
8906     }
8907     return;
8908   }
8909
8910   SMESHDS_Mesh *aMesh = GetMeshDS();
8911   if( !theFace->IsQuadratic() ) {
8912
8913     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8914     int nbLinkNodes = 2 + aNodesToInsert.size();
8915     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8916     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8917     linkNodes[ 0 ] = nodes[ il1 ];
8918     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8919     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8920     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8921       linkNodes[ iNode++ ] = *nIt;
8922     }
8923     // decide how to split a quadrangle: compare possible variants
8924     // and choose which of splits to be a quadrangle
8925     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8926     if ( nbFaceNodes == 3 ) {
8927       iBestQuad = nbSplits;
8928       i4 = i3;
8929     }
8930     else if ( nbFaceNodes == 4 ) {
8931       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8932       double aBestRate = DBL_MAX;
8933       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8934         i1 = 0; i2 = 1;
8935         double aBadRate = 0;
8936         // evaluate elements quality
8937         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8938           if ( iSplit == iQuad ) {
8939             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8940                                    linkNodes[ i2++ ],
8941                                    nodes[ i3 ],
8942                                    nodes[ i4 ]);
8943             aBadRate += getBadRate( &quad, aCrit );
8944           }
8945           else {
8946             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8947                                    linkNodes[ i2++ ],
8948                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8949             aBadRate += getBadRate( &tria, aCrit );
8950           }
8951         }
8952         // choice
8953         if ( aBadRate < aBestRate ) {
8954           iBestQuad = iQuad;
8955           aBestRate = aBadRate;
8956         }
8957       }
8958     }
8959
8960     // create new elements
8961     int aShapeId = FindShape( theFace );
8962
8963     i1 = 0; i2 = 1;
8964     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8965       SMDS_MeshElement* newElem = 0;
8966       if ( iSplit == iBestQuad )
8967         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8968                                   linkNodes[ i2++ ],
8969                                   nodes[ i3 ],
8970                                   nodes[ i4 ]);
8971       else
8972         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8973                                   linkNodes[ i2++ ],
8974                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8975       myLastCreatedElems.Append(newElem);
8976       if ( aShapeId && newElem )
8977         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8978     }
8979
8980     // change nodes of theFace
8981     const SMDS_MeshNode* newNodes[ 4 ];
8982     newNodes[ 0 ] = linkNodes[ i1 ];
8983     newNodes[ 1 ] = linkNodes[ i2 ];
8984     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8985     newNodes[ 3 ] = nodes[ i4 ];
8986     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8987     const SMDS_MeshElement* newElem = 0;
8988     if (iSplit == iBestQuad)
8989       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8990     else
8991       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8992     myLastCreatedElems.Append(newElem);
8993     if ( aShapeId && newElem )
8994       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8995 } // end if(!theFace->IsQuadratic())
8996   else { // theFace is quadratic
8997     // we have to split theFace on simple triangles and one simple quadrangle
8998     int tmp = il1/2;
8999     int nbshift = tmp*2;
9000     // shift nodes in nodes[] by nbshift
9001     int i,j;
9002     for(i=0; i<nbshift; i++) {
9003       const SMDS_MeshNode* n = nodes[0];
9004       for(j=0; j<nbFaceNodes-1; j++) {
9005         nodes[j] = nodes[j+1];
9006       }
9007       nodes[nbFaceNodes-1] = n;
9008     }
9009     il1 = il1 - nbshift;
9010     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9011     //   n0      n1     n2    n0      n1     n2
9012     //     +-----+-----+        +-----+-----+
9013     //      \         /         |           |
9014     //       \       /          |           |
9015     //      n5+     +n3       n7+           +n3
9016     //         \   /            |           |
9017     //          \ /             |           |
9018     //           +              +-----+-----+
9019     //           n4           n6      n5     n4
9020
9021     // create new elements
9022     int aShapeId = FindShape( theFace );
9023
9024     int n1,n2,n3;
9025     if(nbFaceNodes==6) { // quadratic triangle
9026       SMDS_MeshElement* newElem =
9027         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9028       myLastCreatedElems.Append(newElem);
9029       if ( aShapeId && newElem )
9030         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9031       if(theFace->IsMediumNode(nodes[il1])) {
9032         // create quadrangle
9033         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9034         myLastCreatedElems.Append(newElem);
9035         if ( aShapeId && newElem )
9036           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9037         n1 = 1;
9038         n2 = 2;
9039         n3 = 3;
9040       }
9041       else {
9042         // create quadrangle
9043         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9044         myLastCreatedElems.Append(newElem);
9045         if ( aShapeId && newElem )
9046           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9047         n1 = 0;
9048         n2 = 1;
9049         n3 = 5;
9050       }
9051     }
9052     else { // nbFaceNodes==8 - quadratic quadrangle
9053       SMDS_MeshElement* newElem =
9054         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9055       myLastCreatedElems.Append(newElem);
9056       if ( aShapeId && newElem )
9057         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9058       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9059       myLastCreatedElems.Append(newElem);
9060       if ( aShapeId && newElem )
9061         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9062       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9063       myLastCreatedElems.Append(newElem);
9064       if ( aShapeId && newElem )
9065         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9066       if(theFace->IsMediumNode(nodes[il1])) {
9067         // create quadrangle
9068         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9069         myLastCreatedElems.Append(newElem);
9070         if ( aShapeId && newElem )
9071           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9072         n1 = 1;
9073         n2 = 2;
9074         n3 = 3;
9075       }
9076       else {
9077         // create quadrangle
9078         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9079         myLastCreatedElems.Append(newElem);
9080         if ( aShapeId && newElem )
9081           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9082         n1 = 0;
9083         n2 = 1;
9084         n3 = 7;
9085       }
9086     }
9087     // create needed triangles using n1,n2,n3 and inserted nodes
9088     int nbn = 2 + aNodesToInsert.size();
9089     //const SMDS_MeshNode* aNodes[nbn];
9090     vector<const SMDS_MeshNode*> aNodes(nbn);
9091     aNodes[0] = nodes[n1];
9092     aNodes[nbn-1] = nodes[n2];
9093     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9094     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9095       aNodes[iNode++] = *nIt;
9096     }
9097     for(i=1; i<nbn; i++) {
9098       SMDS_MeshElement* newElem =
9099         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9100       myLastCreatedElems.Append(newElem);
9101       if ( aShapeId && newElem )
9102         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9103     }
9104   }
9105   // remove old face
9106   aMesh->RemoveElement(theFace);
9107 }
9108
9109 //=======================================================================
9110 //function : UpdateVolumes
9111 //purpose  :
9112 //=======================================================================
9113 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9114                                       const SMDS_MeshNode*        theBetweenNode2,
9115                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9116 {
9117   myLastCreatedElems.Clear();
9118   myLastCreatedNodes.Clear();
9119
9120   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9121   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9122     const SMDS_MeshElement* elem = invElemIt->next();
9123
9124     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9125     SMDS_VolumeTool aVolume (elem);
9126     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9127       continue;
9128
9129     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9130     int iface, nbFaces = aVolume.NbFaces();
9131     vector<const SMDS_MeshNode *> poly_nodes;
9132     vector<int> quantities (nbFaces);
9133
9134     for (iface = 0; iface < nbFaces; iface++) {
9135       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9136       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9137       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9138
9139       for (int inode = 0; inode < nbFaceNodes; inode++) {
9140         poly_nodes.push_back(faceNodes[inode]);
9141
9142         if (nbInserted == 0) {
9143           if (faceNodes[inode] == theBetweenNode1) {
9144             if (faceNodes[inode + 1] == theBetweenNode2) {
9145               nbInserted = theNodesToInsert.size();
9146
9147               // add nodes to insert
9148               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9149               for (; nIt != theNodesToInsert.end(); nIt++) {
9150                 poly_nodes.push_back(*nIt);
9151               }
9152             }
9153           }
9154           else if (faceNodes[inode] == theBetweenNode2) {
9155             if (faceNodes[inode + 1] == theBetweenNode1) {
9156               nbInserted = theNodesToInsert.size();
9157
9158               // add nodes to insert in reversed order
9159               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9160               nIt--;
9161               for (; nIt != theNodesToInsert.begin(); nIt--) {
9162                 poly_nodes.push_back(*nIt);
9163               }
9164               poly_nodes.push_back(*nIt);
9165             }
9166           }
9167           else {
9168           }
9169         }
9170       }
9171       quantities[iface] = nbFaceNodes + nbInserted;
9172     }
9173
9174     // Replace or update the volume
9175     SMESHDS_Mesh *aMesh = GetMeshDS();
9176
9177     if (elem->IsPoly()) {
9178       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9179
9180     }
9181     else {
9182       int aShapeId = FindShape( elem );
9183
9184       SMDS_MeshElement* newElem =
9185         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9186       myLastCreatedElems.Append(newElem);
9187       if (aShapeId && newElem)
9188         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9189
9190       aMesh->RemoveElement(elem);
9191     }
9192   }
9193 }
9194
9195 //=======================================================================
9196 /*!
9197  * \brief Convert elements contained in a submesh to quadratic
9198  * \return int - nb of checked elements
9199  */
9200 //=======================================================================
9201
9202 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9203                                              SMESH_MesherHelper& theHelper,
9204                                              const bool          theForce3d)
9205 {
9206   int nbElem = 0;
9207   if( !theSm ) return nbElem;
9208
9209   vector<int> nbNodeInFaces;
9210   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9211   while(ElemItr->more())
9212   {
9213     nbElem++;
9214     const SMDS_MeshElement* elem = ElemItr->next();
9215     if( !elem || elem->IsQuadratic() ) continue;
9216
9217     int id = elem->GetID();
9218     int nbNodes = elem->NbNodes();
9219     SMDSAbs_ElementType aType = elem->GetType();
9220
9221     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9222     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9223       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9224
9225     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9226
9227     const SMDS_MeshElement* NewElem = 0;
9228
9229     switch( aType )
9230     {
9231     case SMDSAbs_Edge :
9232       {
9233         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9234         break;
9235       }
9236     case SMDSAbs_Face :
9237       {
9238         switch(nbNodes)
9239         {
9240         case 3:
9241           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9242           break;
9243         case 4:
9244           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9245           break;
9246         default:
9247           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9248           continue;
9249         }
9250         break;
9251       }
9252     case SMDSAbs_Volume :
9253       {
9254         switch(nbNodes)
9255         {
9256         case 4:
9257           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9258           break;
9259         case 5:
9260           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9261           break;
9262         case 6:
9263           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9264           break;
9265         case 8:
9266           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9267                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9268           break;
9269         default:
9270           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9271         }
9272         break;
9273       }
9274     default :
9275       continue;
9276     }
9277     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9278     if( NewElem )
9279       theSm->AddElement( NewElem );
9280   }
9281 //  if (!GetMeshDS()->isCompacted())
9282 //    GetMeshDS()->compactMesh();
9283   return nbElem;
9284 }
9285
9286 //=======================================================================
9287 //function : ConvertToQuadratic
9288 //purpose  :
9289 //=======================================================================
9290 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9291 {
9292   SMESHDS_Mesh* meshDS = GetMeshDS();
9293
9294   SMESH_MesherHelper aHelper(*myMesh);
9295   aHelper.SetIsQuadratic( true );
9296
9297   int nbCheckedElems = 0;
9298   if ( myMesh->HasShapeToMesh() )
9299   {
9300     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9301     {
9302       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9303       while ( smIt->more() ) {
9304         SMESH_subMesh* sm = smIt->next();
9305         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9306           aHelper.SetSubShape( sm->GetSubShape() );
9307           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9308         }
9309       }
9310     }
9311   }
9312   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9313   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9314   {
9315     SMESHDS_SubMesh *smDS = 0;
9316     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9317     while(aEdgeItr->more())
9318     {
9319       const SMDS_MeshEdge* edge = aEdgeItr->next();
9320       if(edge && !edge->IsQuadratic())
9321       {
9322         int id = edge->GetID();
9323         //MESSAGE("edge->GetID() " << id);
9324         const SMDS_MeshNode* n1 = edge->GetNode(0);
9325         const SMDS_MeshNode* n2 = edge->GetNode(1);
9326
9327         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9328
9329         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9330         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9331       }
9332     }
9333     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9334     while(aFaceItr->more())
9335     {
9336       const SMDS_MeshFace* face = aFaceItr->next();
9337       if(!face || face->IsQuadratic() ) continue;
9338
9339       int id = face->GetID();
9340       int nbNodes = face->NbNodes();
9341       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9342
9343       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9344
9345       SMDS_MeshFace * NewFace = 0;
9346       switch(nbNodes)
9347       {
9348       case 3:
9349         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9350         break;
9351       case 4:
9352         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9353         break;
9354       default:
9355         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9356       }
9357       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9358     }
9359     vector<int> nbNodeInFaces;
9360     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9361     while(aVolumeItr->more())
9362     {
9363       const SMDS_MeshVolume* volume = aVolumeItr->next();
9364       if(!volume || volume->IsQuadratic() ) continue;
9365
9366       int id = volume->GetID();
9367       int nbNodes = volume->NbNodes();
9368       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9369       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9370         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9371
9372       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9373
9374       SMDS_MeshVolume * NewVolume = 0;
9375       switch(nbNodes)
9376       {
9377       case 4:
9378         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9379                                       nodes[3], id, theForce3d );
9380         break;
9381       case 5:
9382         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9383                                       nodes[3], nodes[4], id, theForce3d);
9384         break;
9385       case 6:
9386         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9387                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9388         break;
9389       case 8:
9390         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9391                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9392         break;
9393       default:
9394         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9395       }
9396       ReplaceElemInGroups(volume, NewVolume, meshDS);
9397     }
9398   }
9399
9400   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9401   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9402     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9403     aHelper.FixQuadraticElements();
9404   }
9405 }
9406
9407 //================================================================================
9408 /*!
9409  * \brief Makes given elements quadratic
9410  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9411  *  \param theElements - elements to make quadratic 
9412  */
9413 //================================================================================
9414
9415 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9416                                           TIDSortedElemSet& theElements)
9417 {
9418   if ( theElements.empty() ) return;
9419
9420   // we believe that all theElements are of the same type
9421   SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9422   
9423   // get all nodes shared by theElements
9424   TIDSortedNodeSet allNodes;
9425   TIDSortedElemSet::iterator eIt = theElements.begin();
9426   for ( ; eIt != theElements.end(); ++eIt )
9427     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9428
9429   // complete theElements with elements of lower dim whose all nodes are in allNodes
9430
9431   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9432   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9433   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9434   for ( ; nIt != allNodes.end(); ++nIt )
9435   {
9436     const SMDS_MeshNode* n = *nIt;
9437     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9438     while ( invIt->more() )
9439     {
9440       const SMDS_MeshElement* e = invIt->next();
9441       if ( e->IsQuadratic() )
9442       {
9443         quadAdjacentElems[ e->GetType() ].insert( e );
9444         continue;
9445       }
9446       if ( e->GetType() >= elemType )
9447       {
9448         continue; // same type of more complex linear element
9449       }
9450
9451       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9452         continue; // e is already checked
9453
9454       // check nodes
9455       bool allIn = true;
9456       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9457       while ( nodeIt->more() && allIn )
9458         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9459       if ( allIn )
9460         theElements.insert(e );
9461     }
9462   }
9463
9464   SMESH_MesherHelper helper(*myMesh);
9465   helper.SetIsQuadratic( true );
9466
9467   // add links of quadratic adjacent elements to the helper
9468
9469   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9470     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9471           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9472     {
9473       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9474     }
9475   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9476     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9477           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9478     {
9479       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9480     }
9481   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9482     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9483           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9484     {
9485       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9486     }
9487
9488   // make quadratic elements instead of linear ones
9489
9490   SMESHDS_Mesh* meshDS = GetMeshDS();
9491   SMESHDS_SubMesh* smDS = 0;
9492   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9493   {
9494     const SMDS_MeshElement* elem = *eIt;
9495     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9496       continue;
9497
9498     int id = elem->GetID();
9499     SMDSAbs_ElementType type = elem->GetType();
9500     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9501
9502     if ( !smDS || !smDS->Contains( elem ))
9503       smDS = meshDS->MeshElements( elem->getshapeId() );
9504     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9505
9506     SMDS_MeshElement * newElem = 0;
9507     switch( nodes.size() )
9508     {
9509     case 4: // cases for most multiple element types go first (for optimization)
9510       if ( type == SMDSAbs_Volume )
9511         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9512       else
9513         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9514       break;
9515     case 8:
9516       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9517                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9518       break;
9519     case 3:
9520       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9521       break;
9522     case 2:
9523       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9524       break;
9525     case 5:
9526       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9527                                  nodes[4], id, theForce3d);
9528       break;
9529     case 6:
9530       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9531                                  nodes[4], nodes[5], id, theForce3d);
9532       break;
9533     default:;
9534     }
9535     ReplaceElemInGroups( elem, newElem, meshDS);
9536     if( newElem && smDS )
9537       smDS->AddElement( newElem );
9538   }
9539
9540   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9541   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9542     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9543     helper.FixQuadraticElements();
9544   }
9545 }
9546
9547 //=======================================================================
9548 /*!
9549  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9550  * \return int - nb of checked elements
9551  */
9552 //=======================================================================
9553
9554 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9555                                      SMDS_ElemIteratorPtr theItr,
9556                                      const int            theShapeID)
9557 {
9558   int nbElem = 0;
9559   SMESHDS_Mesh* meshDS = GetMeshDS();
9560
9561   while( theItr->more() )
9562   {
9563     const SMDS_MeshElement* elem = theItr->next();
9564     nbElem++;
9565     if( elem && elem->IsQuadratic())
9566     {
9567       int id                    = elem->GetID();
9568       int nbCornerNodes         = elem->NbCornerNodes();
9569       SMDSAbs_ElementType aType = elem->GetType();
9570
9571       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9572
9573       //remove a quadratic element
9574       if ( !theSm || !theSm->Contains( elem ))
9575         theSm = meshDS->MeshElements( elem->getshapeId() );
9576       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9577
9578       // remove medium nodes
9579       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9580         if ( nodes[i]->NbInverseElements() == 0 )
9581           meshDS->RemoveFreeNode( nodes[i], theSm );
9582
9583       // add a linear element
9584       nodes.resize( nbCornerNodes );
9585       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9586       ReplaceElemInGroups(elem, newElem, meshDS);
9587       if( theSm && newElem )
9588         theSm->AddElement( newElem );
9589     }
9590   }
9591   return nbElem;
9592 }
9593
9594 //=======================================================================
9595 //function : ConvertFromQuadratic
9596 //purpose  :
9597 //=======================================================================
9598
9599 bool SMESH_MeshEditor::ConvertFromQuadratic()
9600 {
9601   int nbCheckedElems = 0;
9602   if ( myMesh->HasShapeToMesh() )
9603   {
9604     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9605     {
9606       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9607       while ( smIt->more() ) {
9608         SMESH_subMesh* sm = smIt->next();
9609         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9610           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9611       }
9612     }
9613   }
9614
9615   int totalNbElems =
9616     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9617   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9618   {
9619     SMESHDS_SubMesh *aSM = 0;
9620     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9621   }
9622
9623   return true;
9624 }
9625
9626 namespace
9627 {
9628   //================================================================================
9629   /*!
9630    * \brief Return true if all medium nodes of the element are in the node set
9631    */
9632   //================================================================================
9633
9634   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9635   {
9636     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9637       if ( !nodeSet.count( elem->GetNode(i) ))
9638         return false;
9639     return true;
9640   }
9641 }
9642
9643 //================================================================================
9644 /*!
9645  * \brief Makes given elements linear
9646  */
9647 //================================================================================
9648
9649 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9650 {
9651   if ( theElements.empty() ) return;
9652
9653   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9654   set<int> mediumNodeIDs;
9655   TIDSortedElemSet::iterator eIt = theElements.begin();
9656   for ( ; eIt != theElements.end(); ++eIt )
9657   {
9658     const SMDS_MeshElement* e = *eIt;
9659     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9660       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9661   }
9662
9663   // replace given elements by linear ones
9664   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9665   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9666   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9667
9668   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9669   // except those elements sharing medium nodes of quadratic element whose medium nodes
9670   // are not all in mediumNodeIDs
9671
9672   // get remaining medium nodes
9673   TIDSortedNodeSet mediumNodes;
9674   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9675   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9676     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9677       mediumNodes.insert( mediumNodes.end(), n );
9678
9679   // find more quadratic elements to convert
9680   TIDSortedElemSet moreElemsToConvert;
9681   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9682   for ( ; nIt != mediumNodes.end(); ++nIt )
9683   {
9684     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9685     while ( invIt->more() )
9686     {
9687       const SMDS_MeshElement* e = invIt->next();
9688       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9689       {
9690         // find a more complex element including e and
9691         // whose medium nodes are not in mediumNodes
9692         bool complexFound = false;
9693         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9694         {
9695           SMDS_ElemIteratorPtr invIt2 =
9696             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9697           while ( invIt2->more() )
9698           {
9699             const SMDS_MeshElement* eComplex = invIt2->next();
9700             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9701             {
9702               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9703               if ( nbCommonNodes == e->NbNodes())
9704               {
9705                 complexFound = true;
9706                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9707                 break;
9708               }
9709             }
9710           }
9711         }
9712         if ( !complexFound )
9713           moreElemsToConvert.insert( e );
9714       }
9715     }
9716   }
9717   elemIt = SMDS_ElemIteratorPtr
9718     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9719   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9720 }
9721
9722 //=======================================================================
9723 //function : SewSideElements
9724 //purpose  :
9725 //=======================================================================
9726
9727 SMESH_MeshEditor::Sew_Error
9728 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9729                                    TIDSortedElemSet&    theSide2,
9730                                    const SMDS_MeshNode* theFirstNode1,
9731                                    const SMDS_MeshNode* theFirstNode2,
9732                                    const SMDS_MeshNode* theSecondNode1,
9733                                    const SMDS_MeshNode* theSecondNode2)
9734 {
9735   myLastCreatedElems.Clear();
9736   myLastCreatedNodes.Clear();
9737
9738   MESSAGE ("::::SewSideElements()");
9739   if ( theSide1.size() != theSide2.size() )
9740     return SEW_DIFF_NB_OF_ELEMENTS;
9741
9742   Sew_Error aResult = SEW_OK;
9743   // Algo:
9744   // 1. Build set of faces representing each side
9745   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9746   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9747
9748   // =======================================================================
9749   // 1. Build set of faces representing each side:
9750   // =======================================================================
9751   // a. build set of nodes belonging to faces
9752   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9753   // c. create temporary faces representing side of volumes if correspondent
9754   //    face does not exist
9755
9756   SMESHDS_Mesh* aMesh = GetMeshDS();
9757   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9758   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9759   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9760   set<const SMDS_MeshElement*> volSet1,  volSet2;
9761   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9762   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9763   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9764   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9765   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9766   int iSide, iFace, iNode;
9767
9768   list<const SMDS_MeshElement* > tempFaceList;
9769   for ( iSide = 0; iSide < 2; iSide++ ) {
9770     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9771     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9772     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9773     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9774     set<const SMDS_MeshElement*>::iterator vIt;
9775     TIDSortedElemSet::iterator eIt;
9776     set<const SMDS_MeshNode*>::iterator    nIt;
9777
9778     // check that given nodes belong to given elements
9779     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9780     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9781     int firstIndex = -1, secondIndex = -1;
9782     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9783       const SMDS_MeshElement* elem = *eIt;
9784       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9785       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9786       if ( firstIndex > -1 && secondIndex > -1 ) break;
9787     }
9788     if ( firstIndex < 0 || secondIndex < 0 ) {
9789       // we can simply return until temporary faces created
9790       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9791     }
9792
9793     // -----------------------------------------------------------
9794     // 1a. Collect nodes of existing faces
9795     //     and build set of face nodes in order to detect missing
9796     //     faces corresponding to sides of volumes
9797     // -----------------------------------------------------------
9798
9799     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9800
9801     // loop on the given element of a side
9802     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9803       //const SMDS_MeshElement* elem = *eIt;
9804       const SMDS_MeshElement* elem = *eIt;
9805       if ( elem->GetType() == SMDSAbs_Face ) {
9806         faceSet->insert( elem );
9807         set <const SMDS_MeshNode*> faceNodeSet;
9808         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9809         while ( nodeIt->more() ) {
9810           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9811           nodeSet->insert( n );
9812           faceNodeSet.insert( n );
9813         }
9814         setOfFaceNodeSet.insert( faceNodeSet );
9815       }
9816       else if ( elem->GetType() == SMDSAbs_Volume )
9817         volSet->insert( elem );
9818     }
9819     // ------------------------------------------------------------------------------
9820     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9821     // ------------------------------------------------------------------------------
9822
9823     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9824       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9825       while ( fIt->more() ) { // loop on faces sharing a node
9826         const SMDS_MeshElement* f = fIt->next();
9827         if ( faceSet->find( f ) == faceSet->end() ) {
9828           // check if all nodes are in nodeSet and
9829           // complete setOfFaceNodeSet if they are
9830           set <const SMDS_MeshNode*> faceNodeSet;
9831           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9832           bool allInSet = true;
9833           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9834             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9835             if ( nodeSet->find( n ) == nodeSet->end() )
9836               allInSet = false;
9837             else
9838               faceNodeSet.insert( n );
9839           }
9840           if ( allInSet ) {
9841             faceSet->insert( f );
9842             setOfFaceNodeSet.insert( faceNodeSet );
9843           }
9844         }
9845       }
9846     }
9847
9848     // -------------------------------------------------------------------------
9849     // 1c. Create temporary faces representing sides of volumes if correspondent
9850     //     face does not exist
9851     // -------------------------------------------------------------------------
9852
9853     if ( !volSet->empty() ) {
9854       //int nodeSetSize = nodeSet->size();
9855
9856       // loop on given volumes
9857       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9858         SMDS_VolumeTool vol (*vIt);
9859         // loop on volume faces: find free faces
9860         // --------------------------------------
9861         list<const SMDS_MeshElement* > freeFaceList;
9862         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9863           if ( !vol.IsFreeFace( iFace ))
9864             continue;
9865           // check if there is already a face with same nodes in a face set
9866           const SMDS_MeshElement* aFreeFace = 0;
9867           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9868           int nbNodes = vol.NbFaceNodes( iFace );
9869           set <const SMDS_MeshNode*> faceNodeSet;
9870           vol.GetFaceNodes( iFace, faceNodeSet );
9871           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9872           if ( isNewFace ) {
9873             // no such a face is given but it still can exist, check it
9874             if ( nbNodes == 3 ) {
9875               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9876             }
9877             else if ( nbNodes == 4 ) {
9878               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9879             }
9880             else {
9881               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9882               aFreeFace = aMesh->FindFace(poly_nodes);
9883             }
9884           }
9885           if ( !aFreeFace ) {
9886             // create a temporary face
9887             if ( nbNodes == 3 ) {
9888               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9889               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9890             }
9891             else if ( nbNodes == 4 ) {
9892               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9893               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9894             }
9895             else {
9896               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9897               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9898               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9899             }
9900           }
9901           if ( aFreeFace ) {
9902             freeFaceList.push_back( aFreeFace );
9903             tempFaceList.push_back( aFreeFace );
9904           }
9905
9906         } // loop on faces of a volume
9907
9908         // choose one of several free faces
9909         // --------------------------------------
9910         if ( freeFaceList.size() > 1 ) {
9911           // choose a face having max nb of nodes shared by other elems of a side
9912           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9913           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9914           while ( fIt != freeFaceList.end() ) { // loop on free faces
9915             int nbSharedNodes = 0;
9916             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9917             while ( nodeIt->more() ) { // loop on free face nodes
9918               const SMDS_MeshNode* n =
9919                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9920               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9921               while ( invElemIt->more() ) {
9922                 const SMDS_MeshElement* e = invElemIt->next();
9923                 if ( faceSet->find( e ) != faceSet->end() )
9924                   nbSharedNodes++;
9925                 if ( elemSet->find( e ) != elemSet->end() )
9926                   nbSharedNodes++;
9927               }
9928             }
9929             if ( nbSharedNodes >= maxNbNodes ) {
9930               maxNbNodes = nbSharedNodes;
9931               fIt++;
9932             }
9933             else
9934               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9935           }
9936           if ( freeFaceList.size() > 1 )
9937           {
9938             // could not choose one face, use another way
9939             // choose a face most close to the bary center of the opposite side
9940             gp_XYZ aBC( 0., 0., 0. );
9941             set <const SMDS_MeshNode*> addedNodes;
9942             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9943             eIt = elemSet2->begin();
9944             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9945               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9946               while ( nodeIt->more() ) { // loop on free face nodes
9947                 const SMDS_MeshNode* n =
9948                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9949                 if ( addedNodes.insert( n ).second )
9950                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9951               }
9952             }
9953             aBC /= addedNodes.size();
9954             double minDist = DBL_MAX;
9955             fIt = freeFaceList.begin();
9956             while ( fIt != freeFaceList.end() ) { // loop on free faces
9957               double dist = 0;
9958               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9959               while ( nodeIt->more() ) { // loop on free face nodes
9960                 const SMDS_MeshNode* n =
9961                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9962                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9963                 dist += ( aBC - p ).SquareModulus();
9964               }
9965               if ( dist < minDist ) {
9966                 minDist = dist;
9967                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9968               }
9969               else
9970                 fIt = freeFaceList.erase( fIt++ );
9971             }
9972           }
9973         } // choose one of several free faces of a volume
9974
9975         if ( freeFaceList.size() == 1 ) {
9976           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9977           faceSet->insert( aFreeFace );
9978           // complete a node set with nodes of a found free face
9979           //           for ( iNode = 0; iNode < ; iNode++ )
9980           //             nodeSet->insert( fNodes[ iNode ] );
9981         }
9982
9983       } // loop on volumes of a side
9984
9985       //       // complete a set of faces if new nodes in a nodeSet appeared
9986       //       // ----------------------------------------------------------
9987       //       if ( nodeSetSize != nodeSet->size() ) {
9988       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9989       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9990       //           while ( fIt->more() ) { // loop on faces sharing a node
9991       //             const SMDS_MeshElement* f = fIt->next();
9992       //             if ( faceSet->find( f ) == faceSet->end() ) {
9993       //               // check if all nodes are in nodeSet and
9994       //               // complete setOfFaceNodeSet if they are
9995       //               set <const SMDS_MeshNode*> faceNodeSet;
9996       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9997       //               bool allInSet = true;
9998       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9999       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10000       //                 if ( nodeSet->find( n ) == nodeSet->end() )
10001       //                   allInSet = false;
10002       //                 else
10003       //                   faceNodeSet.insert( n );
10004       //               }
10005       //               if ( allInSet ) {
10006       //                 faceSet->insert( f );
10007       //                 setOfFaceNodeSet.insert( faceNodeSet );
10008       //               }
10009       //             }
10010       //           }
10011       //         }
10012       //       }
10013     } // Create temporary faces, if there are volumes given
10014   } // loop on sides
10015
10016   if ( faceSet1.size() != faceSet2.size() ) {
10017     // delete temporary faces: they are in reverseElements of actual nodes
10018 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10019 //    while ( tmpFaceIt->more() )
10020 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10021 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10022 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10023 //      aMesh->RemoveElement(*tmpFaceIt);
10024     MESSAGE("Diff nb of faces");
10025     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10026   }
10027
10028   // ============================================================
10029   // 2. Find nodes to merge:
10030   //              bind a node to remove to a node to put instead
10031   // ============================================================
10032
10033   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10034   if ( theFirstNode1 != theFirstNode2 )
10035     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10036   if ( theSecondNode1 != theSecondNode2 )
10037     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10038
10039   LinkID_Gen aLinkID_Gen( GetMeshDS() );
10040   set< long > linkIdSet; // links to process
10041   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10042
10043   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10044   list< NLink > linkList[2];
10045   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10046   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10047   // loop on links in linkList; find faces by links and append links
10048   // of the found faces to linkList
10049   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10050   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10051     NLink link[] = { *linkIt[0], *linkIt[1] };
10052     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10053     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10054       continue;
10055
10056     // by links, find faces in the face sets,
10057     // and find indices of link nodes in the found faces;
10058     // in a face set, there is only one or no face sharing a link
10059     // ---------------------------------------------------------------
10060
10061     const SMDS_MeshElement* face[] = { 0, 0 };
10062     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10063     vector<const SMDS_MeshNode*> fnodes1(9);
10064     vector<const SMDS_MeshNode*> fnodes2(9);
10065     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10066     vector<const SMDS_MeshNode*> notLinkNodes1(6);
10067     vector<const SMDS_MeshNode*> notLinkNodes2(6);
10068     int iLinkNode[2][2];
10069     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10070       const SMDS_MeshNode* n1 = link[iSide].first;
10071       const SMDS_MeshNode* n2 = link[iSide].second;
10072       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10073       set< const SMDS_MeshElement* > fMap;
10074       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10075         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10076         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10077         while ( fIt->more() ) { // loop on faces sharing a node
10078           const SMDS_MeshElement* f = fIt->next();
10079           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10080               ! fMap.insert( f ).second ) // f encounters twice
10081           {
10082             if ( face[ iSide ] ) {
10083               MESSAGE( "2 faces per link " );
10084               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10085               break;
10086             }
10087             face[ iSide ] = f;
10088             faceSet->erase( f );
10089             // get face nodes and find ones of a link
10090             iNode = 0;
10091             int nbl = -1;
10092             if(f->IsPoly()) {
10093               if(iSide==0) {
10094                 fnodes1.resize(f->NbNodes()+1);
10095                 notLinkNodes1.resize(f->NbNodes()-2);
10096               }
10097               else {
10098                 fnodes2.resize(f->NbNodes()+1);
10099                 notLinkNodes2.resize(f->NbNodes()-2);
10100               }
10101             }
10102             if(!f->IsQuadratic()) {
10103               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10104               while ( nIt->more() ) {
10105                 const SMDS_MeshNode* n =
10106                   static_cast<const SMDS_MeshNode*>( nIt->next() );
10107                 if ( n == n1 ) {
10108                   iLinkNode[ iSide ][ 0 ] = iNode;
10109                 }
10110                 else if ( n == n2 ) {
10111                   iLinkNode[ iSide ][ 1 ] = iNode;
10112                 }
10113                 //else if ( notLinkNodes[ iSide ][ 0 ] )
10114                 //  notLinkNodes[ iSide ][ 1 ] = n;
10115                 //else
10116                 //  notLinkNodes[ iSide ][ 0 ] = n;
10117                 else {
10118                   nbl++;
10119                   if(iSide==0)
10120                     notLinkNodes1[nbl] = n;
10121                   //notLinkNodes1.push_back(n);
10122                   else
10123                     notLinkNodes2[nbl] = n;
10124                   //notLinkNodes2.push_back(n);
10125                 }
10126                 //faceNodes[ iSide ][ iNode++ ] = n;
10127                 if(iSide==0) {
10128                   fnodes1[iNode++] = n;
10129                 }
10130                 else {
10131                   fnodes2[iNode++] = n;
10132                 }
10133               }
10134             }
10135             else { // f->IsQuadratic()
10136               const SMDS_VtkFace* F =
10137                 dynamic_cast<const SMDS_VtkFace*>(f);
10138               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10139               // use special nodes iterator
10140               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10141               while ( anIter->more() ) {
10142                 const SMDS_MeshNode* n =
10143                   static_cast<const SMDS_MeshNode*>( anIter->next() );
10144                 if ( n == n1 ) {
10145                   iLinkNode[ iSide ][ 0 ] = iNode;
10146                 }
10147                 else if ( n == n2 ) {
10148                   iLinkNode[ iSide ][ 1 ] = iNode;
10149                 }
10150                 else {
10151                   nbl++;
10152                   if(iSide==0) {
10153                     notLinkNodes1[nbl] = n;
10154                   }
10155                   else {
10156                     notLinkNodes2[nbl] = n;
10157                   }
10158                 }
10159                 if(iSide==0) {
10160                   fnodes1[iNode++] = n;
10161                 }
10162                 else {
10163                   fnodes2[iNode++] = n;
10164                 }
10165               }
10166             }
10167             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10168             if(iSide==0) {
10169               fnodes1[iNode] = fnodes1[0];
10170             }
10171             else {
10172               fnodes2[iNode] = fnodes1[0];
10173             }
10174           }
10175         }
10176       }
10177     }
10178
10179     // check similarity of elements of the sides
10180     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10181       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10182       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10183         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10184       }
10185       else {
10186         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10187       }
10188       break; // do not return because it s necessary to remove tmp faces
10189     }
10190
10191     // set nodes to merge
10192     // -------------------
10193
10194     if ( face[0] && face[1] )  {
10195       int nbNodes = face[0]->NbNodes();
10196       if ( nbNodes != face[1]->NbNodes() ) {
10197         MESSAGE("Diff nb of face nodes");
10198         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10199         break; // do not return because it s necessary to remove tmp faces
10200       }
10201       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10202       if ( nbNodes == 3 ) {
10203         //nReplaceMap.insert( TNodeNodeMap::value_type
10204         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10205         nReplaceMap.insert( TNodeNodeMap::value_type
10206                             ( notLinkNodes1[0], notLinkNodes2[0] ));
10207       }
10208       else {
10209         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10210           // analyse link orientation in faces
10211           int i1 = iLinkNode[ iSide ][ 0 ];
10212           int i2 = iLinkNode[ iSide ][ 1 ];
10213           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10214           // if notLinkNodes are the first and the last ones, then
10215           // their order does not correspond to the link orientation
10216           if (( i1 == 1 && i2 == 2 ) ||
10217               ( i1 == 2 && i2 == 1 ))
10218             reverse[ iSide ] = !reverse[ iSide ];
10219         }
10220         if ( reverse[0] == reverse[1] ) {
10221           //nReplaceMap.insert( TNodeNodeMap::value_type
10222           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10223           //nReplaceMap.insert( TNodeNodeMap::value_type
10224           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10225           for(int nn=0; nn<nbNodes-2; nn++) {
10226             nReplaceMap.insert( TNodeNodeMap::value_type
10227                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10228           }
10229         }
10230         else {
10231           //nReplaceMap.insert( TNodeNodeMap::value_type
10232           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10233           //nReplaceMap.insert( TNodeNodeMap::value_type
10234           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10235           for(int nn=0; nn<nbNodes-2; nn++) {
10236             nReplaceMap.insert( TNodeNodeMap::value_type
10237                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10238           }
10239         }
10240       }
10241
10242       // add other links of the faces to linkList
10243       // -----------------------------------------
10244
10245       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10246       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10247         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10248         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10249         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10250         if ( !iter_isnew.second ) { // already in a set: no need to process
10251           linkIdSet.erase( iter_isnew.first );
10252         }
10253         else // new in set == encountered for the first time: add
10254         {
10255           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10256           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10257           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10258           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10259           linkList[0].push_back ( NLink( n1, n2 ));
10260           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10261         }
10262       }
10263     } // 2 faces found
10264   } // loop on link lists
10265
10266   if ( aResult == SEW_OK &&
10267        ( linkIt[0] != linkList[0].end() ||
10268          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10269     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10270              " " << (faceSetPtr[1]->empty()));
10271     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10272   }
10273
10274   // ====================================================================
10275   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10276   // ====================================================================
10277
10278   // delete temporary faces: they are in reverseElements of actual nodes
10279 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10280 //  while ( tmpFaceIt->more() )
10281 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10282 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10283 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10284 //    aMesh->RemoveElement(*tmpFaceIt);
10285
10286   if ( aResult != SEW_OK)
10287     return aResult;
10288
10289   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10290   // loop on nodes replacement map
10291   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10292   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10293     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10294       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10295       nodeIDsToRemove.push_back( nToRemove->GetID() );
10296       // loop on elements sharing nToRemove
10297       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10298       while ( invElemIt->more() ) {
10299         const SMDS_MeshElement* e = invElemIt->next();
10300         // get a new suite of nodes: make replacement
10301         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10302         vector< const SMDS_MeshNode*> nodes( nbNodes );
10303         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10304         while ( nIt->more() ) {
10305           const SMDS_MeshNode* n =
10306             static_cast<const SMDS_MeshNode*>( nIt->next() );
10307           nnIt = nReplaceMap.find( n );
10308           if ( nnIt != nReplaceMap.end() ) {
10309             nbReplaced++;
10310             n = (*nnIt).second;
10311           }
10312           nodes[ i++ ] = n;
10313         }
10314         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10315         //         elemIDsToRemove.push_back( e->GetID() );
10316         //       else
10317         if ( nbReplaced )
10318           {
10319             SMDSAbs_ElementType etyp = e->GetType();
10320             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10321             if (newElem)
10322               {
10323                 myLastCreatedElems.Append(newElem);
10324                 AddToSameGroups(newElem, e, aMesh);
10325                 int aShapeId = e->getshapeId();
10326                 if ( aShapeId )
10327                   {
10328                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10329                   }
10330               }
10331             aMesh->RemoveElement(e);
10332           }
10333       }
10334     }
10335
10336   Remove( nodeIDsToRemove, true );
10337
10338   return aResult;
10339 }
10340
10341 //================================================================================
10342 /*!
10343  * \brief Find corresponding nodes in two sets of faces
10344  * \param theSide1 - first face set
10345  * \param theSide2 - second first face
10346  * \param theFirstNode1 - a boundary node of set 1
10347  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10348  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10349  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10350  * \param nReplaceMap - output map of corresponding nodes
10351  * \return bool  - is a success or not
10352  */
10353 //================================================================================
10354
10355 #ifdef _DEBUG_
10356 //#define DEBUG_MATCHING_NODES
10357 #endif
10358
10359 SMESH_MeshEditor::Sew_Error
10360 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10361                                     set<const SMDS_MeshElement*>& theSide2,
10362                                     const SMDS_MeshNode*          theFirstNode1,
10363                                     const SMDS_MeshNode*          theFirstNode2,
10364                                     const SMDS_MeshNode*          theSecondNode1,
10365                                     const SMDS_MeshNode*          theSecondNode2,
10366                                     TNodeNodeMap &                nReplaceMap)
10367 {
10368   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10369
10370   nReplaceMap.clear();
10371   if ( theFirstNode1 != theFirstNode2 )
10372     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10373   if ( theSecondNode1 != theSecondNode2 )
10374     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10375
10376   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10377   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10378
10379   list< NLink > linkList[2];
10380   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10381   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10382
10383   // loop on links in linkList; find faces by links and append links
10384   // of the found faces to linkList
10385   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10386   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10387     NLink link[] = { *linkIt[0], *linkIt[1] };
10388     if ( linkSet.find( link[0] ) == linkSet.end() )
10389       continue;
10390
10391     // by links, find faces in the face sets,
10392     // and find indices of link nodes in the found faces;
10393     // in a face set, there is only one or no face sharing a link
10394     // ---------------------------------------------------------------
10395
10396     const SMDS_MeshElement* face[] = { 0, 0 };
10397     list<const SMDS_MeshNode*> notLinkNodes[2];
10398     //bool reverse[] = { false, false }; // order of notLinkNodes
10399     int nbNodes[2];
10400     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10401     {
10402       const SMDS_MeshNode* n1 = link[iSide].first;
10403       const SMDS_MeshNode* n2 = link[iSide].second;
10404       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10405       set< const SMDS_MeshElement* > facesOfNode1;
10406       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10407       {
10408         // during a loop of the first node, we find all faces around n1,
10409         // during a loop of the second node, we find one face sharing both n1 and n2
10410         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10411         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10412         while ( fIt->more() ) { // loop on faces sharing a node
10413           const SMDS_MeshElement* f = fIt->next();
10414           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10415               ! facesOfNode1.insert( f ).second ) // f encounters twice
10416           {
10417             if ( face[ iSide ] ) {
10418               MESSAGE( "2 faces per link " );
10419               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10420             }
10421             face[ iSide ] = f;
10422             faceSet->erase( f );
10423
10424             // get not link nodes
10425             int nbN = f->NbNodes();
10426             if ( f->IsQuadratic() )
10427               nbN /= 2;
10428             nbNodes[ iSide ] = nbN;
10429             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10430             int i1 = f->GetNodeIndex( n1 );
10431             int i2 = f->GetNodeIndex( n2 );
10432             int iEnd = nbN, iBeg = -1, iDelta = 1;
10433             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10434             if ( reverse ) {
10435               std::swap( iEnd, iBeg ); iDelta = -1;
10436             }
10437             int i = i2;
10438             while ( true ) {
10439               i += iDelta;
10440               if ( i == iEnd ) i = iBeg + iDelta;
10441               if ( i == i1 ) break;
10442               nodes.push_back ( f->GetNode( i ) );
10443             }
10444           }
10445         }
10446       }
10447     }
10448     // check similarity of elements of the sides
10449     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10450       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10451       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10452         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10453       }
10454       else {
10455         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10456       }
10457     }
10458
10459     // set nodes to merge
10460     // -------------------
10461
10462     if ( face[0] && face[1] )  {
10463       if ( nbNodes[0] != nbNodes[1] ) {
10464         MESSAGE("Diff nb of face nodes");
10465         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10466       }
10467 #ifdef DEBUG_MATCHING_NODES
10468       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10469                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10470                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10471 #endif
10472       int nbN = nbNodes[0];
10473       {
10474         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10475         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10476         for ( int i = 0 ; i < nbN - 2; ++i ) {
10477 #ifdef DEBUG_MATCHING_NODES
10478           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10479 #endif
10480           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10481         }
10482       }
10483
10484       // add other links of the face 1 to linkList
10485       // -----------------------------------------
10486
10487       const SMDS_MeshElement* f0 = face[0];
10488       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10489       for ( int i = 0; i < nbN; i++ )
10490       {
10491         const SMDS_MeshNode* n2 = f0->GetNode( i );
10492         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10493           linkSet.insert( SMESH_TLink( n1, n2 ));
10494         if ( !iter_isnew.second ) { // already in a set: no need to process
10495           linkSet.erase( iter_isnew.first );
10496         }
10497         else // new in set == encountered for the first time: add
10498         {
10499 #ifdef DEBUG_MATCHING_NODES
10500           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10501                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10502 #endif
10503           linkList[0].push_back ( NLink( n1, n2 ));
10504           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10505         }
10506         n1 = n2;
10507       }
10508     } // 2 faces found
10509   } // loop on link lists
10510
10511   return SEW_OK;
10512 }
10513
10514 //================================================================================
10515 /*!
10516   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10517   \param theElems - the list of elements (edges or faces) to be replicated
10518   The nodes for duplication could be found from these elements
10519   \param theNodesNot - list of nodes to NOT replicate
10520   \param theAffectedElems - the list of elements (cells and edges) to which the 
10521   replicated nodes should be associated to.
10522   \return TRUE if operation has been completed successfully, FALSE otherwise
10523 */
10524 //================================================================================
10525
10526 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10527                                     const TIDSortedElemSet& theNodesNot,
10528                                     const TIDSortedElemSet& theAffectedElems )
10529 {
10530   myLastCreatedElems.Clear();
10531   myLastCreatedNodes.Clear();
10532
10533   if ( theElems.size() == 0 )
10534     return false;
10535
10536   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10537   if ( !aMeshDS )
10538     return false;
10539
10540   bool res = false;
10541   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10542   // duplicate elements and nodes
10543   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10544   // replce nodes by duplications
10545   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10546   return res;
10547 }
10548
10549 //================================================================================
10550 /*!
10551   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10552   \param theMeshDS - mesh instance
10553   \param theElems - the elements replicated or modified (nodes should be changed)
10554   \param theNodesNot - nodes to NOT replicate
10555   \param theNodeNodeMap - relation of old node to new created node
10556   \param theIsDoubleElem - flag os to replicate element or modify
10557   \return TRUE if operation has been completed successfully, FALSE otherwise
10558 */
10559 //================================================================================
10560
10561 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10562                                     const TIDSortedElemSet& theElems,
10563                                     const TIDSortedElemSet& theNodesNot,
10564                                     std::map< const SMDS_MeshNode*,
10565                                     const SMDS_MeshNode* >& theNodeNodeMap,
10566                                     const bool theIsDoubleElem )
10567 {
10568   MESSAGE("doubleNodes");
10569   // iterate on through element and duplicate them (by nodes duplication)
10570   bool res = false;
10571   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10572   for ( ;  elemItr != theElems.end(); ++elemItr )
10573   {
10574     const SMDS_MeshElement* anElem = *elemItr;
10575     if (!anElem)
10576       continue;
10577
10578     bool isDuplicate = false;
10579     // duplicate nodes to duplicate element
10580     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10581     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10582     int ind = 0;
10583     while ( anIter->more() ) 
10584     { 
10585
10586       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10587       SMDS_MeshNode* aNewNode = aCurrNode;
10588       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10589         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10590       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10591       {
10592         // duplicate node
10593         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10594         theNodeNodeMap[ aCurrNode ] = aNewNode;
10595         myLastCreatedNodes.Append( aNewNode );
10596       }
10597       isDuplicate |= (aCurrNode != aNewNode);
10598       newNodes[ ind++ ] = aNewNode;
10599     }
10600     if ( !isDuplicate )
10601       continue;
10602
10603     if ( theIsDoubleElem )
10604       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10605     else
10606       {
10607       MESSAGE("ChangeElementNodes");
10608       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10609       }
10610     res = true;
10611   }
10612   return res;
10613 }
10614
10615 //================================================================================
10616 /*!
10617   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10618   \param theNodes - identifiers of nodes to be doubled
10619   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10620          nodes. If list of element identifiers is empty then nodes are doubled but 
10621          they not assigned to elements
10622   \return TRUE if operation has been completed successfully, FALSE otherwise
10623 */
10624 //================================================================================
10625
10626 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10627                                     const std::list< int >& theListOfModifiedElems )
10628 {
10629   MESSAGE("DoubleNodes");
10630   myLastCreatedElems.Clear();
10631   myLastCreatedNodes.Clear();
10632
10633   if ( theListOfNodes.size() == 0 )
10634     return false;
10635
10636   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10637   if ( !aMeshDS )
10638     return false;
10639
10640   // iterate through nodes and duplicate them
10641
10642   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10643
10644   std::list< int >::const_iterator aNodeIter;
10645   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10646   {
10647     int aCurr = *aNodeIter;
10648     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10649     if ( !aNode )
10650       continue;
10651
10652     // duplicate node
10653
10654     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10655     if ( aNewNode )
10656     {
10657       anOldNodeToNewNode[ aNode ] = aNewNode;
10658       myLastCreatedNodes.Append( aNewNode );
10659     }
10660   }
10661
10662   // Create map of new nodes for modified elements
10663
10664   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10665
10666   std::list< int >::const_iterator anElemIter;
10667   for ( anElemIter = theListOfModifiedElems.begin(); 
10668         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10669   {
10670     int aCurr = *anElemIter;
10671     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10672     if ( !anElem )
10673       continue;
10674
10675     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10676
10677     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10678     int ind = 0;
10679     while ( anIter->more() ) 
10680     { 
10681       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10682       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10683       {
10684         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10685         aNodeArr[ ind++ ] = aNewNode;
10686       }
10687       else
10688         aNodeArr[ ind++ ] = aCurrNode;
10689     }
10690     anElemToNodes[ anElem ] = aNodeArr;
10691   }
10692
10693   // Change nodes of elements  
10694
10695   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10696     anElemToNodesIter = anElemToNodes.begin();
10697   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10698   {
10699     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10700     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10701     if ( anElem )
10702       {
10703       MESSAGE("ChangeElementNodes");
10704       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10705       }
10706   }
10707
10708   return true;
10709 }
10710
10711 namespace {
10712
10713   //================================================================================
10714   /*!
10715   \brief Check if element located inside shape
10716   \return TRUE if IN or ON shape, FALSE otherwise
10717   */
10718   //================================================================================
10719
10720   template<class Classifier>
10721   bool isInside(const SMDS_MeshElement* theElem,
10722                 Classifier&             theClassifier,
10723                 const double            theTol)
10724   {
10725     gp_XYZ centerXYZ (0, 0, 0);
10726     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10727     while (aNodeItr->more())
10728       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10729
10730     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10731     theClassifier.Perform(aPnt, theTol);
10732     TopAbs_State aState = theClassifier.State();
10733     return (aState == TopAbs_IN || aState == TopAbs_ON );
10734   }
10735
10736   //================================================================================
10737   /*!
10738    * \brief Classifier of the 3D point on the TopoDS_Face
10739    *        with interaface suitable for isInside()
10740    */
10741   //================================================================================
10742
10743   struct _FaceClassifier
10744   {
10745     Extrema_ExtPS       _extremum;
10746     BRepAdaptor_Surface _surface;
10747     TopAbs_State        _state;
10748
10749     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10750     {
10751       _extremum.Initialize( _surface,
10752                             _surface.FirstUParameter(), _surface.LastUParameter(),
10753                             _surface.FirstVParameter(), _surface.LastVParameter(),
10754                             _surface.Tolerance(), _surface.Tolerance() );
10755     }
10756     void Perform(const gp_Pnt& aPnt, double theTol)
10757     {
10758       _state = TopAbs_OUT;
10759       _extremum.Perform(aPnt);
10760       if ( _extremum.IsDone() )
10761         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10762           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10763     }
10764     TopAbs_State State() const
10765     {
10766       return _state;
10767     }
10768   };
10769 }
10770
10771 //================================================================================
10772 /*!
10773   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10774   \param theElems - group of of elements (edges or faces) to be replicated
10775   \param theNodesNot - group of nodes not to replicate
10776   \param theShape - shape to detect affected elements (element which geometric center
10777   located on or inside shape).
10778   The replicated nodes should be associated to affected elements.
10779   \return TRUE if operation has been completed successfully, FALSE otherwise
10780 */
10781 //================================================================================
10782
10783 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10784                                             const TIDSortedElemSet& theNodesNot,
10785                                             const TopoDS_Shape&     theShape )
10786 {
10787   if ( theShape.IsNull() )
10788     return false;
10789
10790   const double aTol = Precision::Confusion();
10791   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10792   auto_ptr<_FaceClassifier>              aFaceClassifier;
10793   if ( theShape.ShapeType() == TopAbs_SOLID )
10794   {
10795     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10796     bsc3d->PerformInfinitePoint(aTol);
10797   }
10798   else if (theShape.ShapeType() == TopAbs_FACE )
10799   {
10800     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10801   }
10802
10803   // iterates on indicated elements and get elements by back references from their nodes
10804   TIDSortedElemSet anAffected;
10805   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10806   for ( ;  elemItr != theElems.end(); ++elemItr )
10807   {
10808     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10809     if (!anElem)
10810       continue;
10811
10812     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10813     while ( nodeItr->more() )
10814     {
10815       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10816       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10817         continue;
10818       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10819       while ( backElemItr->more() )
10820       {
10821         const SMDS_MeshElement* curElem = backElemItr->next();
10822         if ( curElem && theElems.find(curElem) == theElems.end() &&
10823              ( bsc3d.get() ?
10824                isInside( curElem, *bsc3d, aTol ) :
10825                isInside( curElem, *aFaceClassifier, aTol )))
10826           anAffected.insert( curElem );
10827       }
10828     }
10829   }
10830   return DoubleNodes( theElems, theNodesNot, anAffected );
10831 }
10832
10833 /*!
10834  *  \brief compute an oriented angle between two planes defined by four points.
10835  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10836  *  @param p0 base of the rotation axe
10837  *  @param p1 extremity of the rotation axe
10838  *  @param g1 belongs to the first plane
10839  *  @param g2 belongs to the second plane
10840  */
10841 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10842 {
10843 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10844 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10845 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10846 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10847   gp_Vec vref(p0, p1);
10848   gp_Vec v1(p0, g1);
10849   gp_Vec v2(p0, g2);
10850   gp_Vec n1 = vref.Crossed(v1);
10851   gp_Vec n2 = vref.Crossed(v2);
10852   return n2.AngleWithRef(n1, vref);
10853 }
10854
10855 /*!
10856  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10857  * The list of groups must describe a partition of the mesh volumes.
10858  * The nodes of the internal faces at the boundaries of the groups are doubled.
10859  * In option, the internal faces are replaced by flat elements.
10860  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10861  * The flat elements are stored in groups of volumes.
10862  * @param theElems - list of groups of volumes, where a group of volume is a set of
10863  * SMDS_MeshElements sorted by Id.
10864  * @param createJointElems - if TRUE, create the elements
10865  * @return TRUE if operation has been completed successfully, FALSE otherwise
10866  */
10867 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10868                                                      bool createJointElems)
10869 {
10870   MESSAGE("----------------------------------------------");
10871   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10872   MESSAGE("----------------------------------------------");
10873
10874   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10875   meshDS->BuildDownWardConnectivity(true);
10876   CHRONO(50);
10877   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10878
10879   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10880   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10881   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10882
10883   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10884   std::map<int,int>celldom; // cell vtkId --> domain
10885   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10886   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10887   faceDomains.clear();
10888   celldom.clear();
10889   cellDomains.clear();
10890   nodeDomains.clear();
10891   std::map<int,int> emptyMap;
10892   std::set<int> emptySet;
10893   emptyMap.clear();
10894
10895   for (int idom = 0; idom < theElems.size(); idom++)
10896     {
10897
10898       // --- build a map (face to duplicate --> volume to modify)
10899       //     with all the faces shared by 2 domains (group of elements)
10900       //     and corresponding volume of this domain, for each shared face.
10901       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10902
10903       const TIDSortedElemSet& domain = theElems[idom];
10904       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10905       for (; elemItr != domain.end(); ++elemItr)
10906         {
10907           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10908           if (!anElem)
10909             continue;
10910           int vtkId = anElem->getVtkId();
10911           int neighborsVtkIds[NBMAXNEIGHBORS];
10912           int downIds[NBMAXNEIGHBORS];
10913           unsigned char downTypes[NBMAXNEIGHBORS];
10914           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10915           for (int n = 0; n < nbNeighbors; n++)
10916             {
10917               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10918               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10919               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10920                 {
10921                   DownIdType face(downIds[n], downTypes[n]);
10922                   if (!faceDomains.count(face))
10923                     faceDomains[face] = emptyMap; // create an empty entry for face
10924                   if (!faceDomains[face].count(idom))
10925                     {
10926                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10927                       celldom[vtkId] = idom;
10928                     }
10929                 }
10930             }
10931         }
10932     }
10933
10934   //MESSAGE("Number of shared faces " << faceDomains.size());
10935   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10936
10937   // --- explore the shared faces domain by domain,
10938   //     explore the nodes of the face and see if they belong to a cell in the domain,
10939   //     which has only a node or an edge on the border (not a shared face)
10940
10941   for (int idomain = 0; idomain < theElems.size(); idomain++)
10942     {
10943       const TIDSortedElemSet& domain = theElems[idomain];
10944       itface = faceDomains.begin();
10945       for (; itface != faceDomains.end(); ++itface)
10946         {
10947           std::map<int, int> domvol = itface->second;
10948           if (!domvol.count(idomain))
10949             continue;
10950           DownIdType face = itface->first;
10951           //MESSAGE(" --- face " << face.cellId);
10952           std::set<int> oldNodes;
10953           oldNodes.clear();
10954           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10955           std::set<int>::iterator itn = oldNodes.begin();
10956           for (; itn != oldNodes.end(); ++itn)
10957             {
10958               int oldId = *itn;
10959               //MESSAGE("     node " << oldId);
10960               std::set<int> cells;
10961               cells.clear();
10962               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10963               for (int i=0; i<l.ncells; i++)
10964                 {
10965                   int vtkId = l.cells[i];
10966                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10967                   if (!domain.count(anElem))
10968                     continue;
10969                   int vtkType = grid->GetCellType(vtkId);
10970                   int downId = grid->CellIdToDownId(vtkId);
10971                   DownIdType aCell(downId, vtkType);
10972                   if (celldom.count(vtkId))
10973                     continue;
10974                   cellDomains[aCell][idomain] = vtkId;
10975                   celldom[vtkId] = idomain;
10976                 }
10977             }
10978         }
10979     }
10980
10981   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10982   //     for each shared face, get the nodes
10983   //     for each node, for each domain of the face, create a clone of the node
10984
10985   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10986   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10987   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
10988
10989   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10990   std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
10991
10992   for (int idomain = 0; idomain < theElems.size(); idomain++)
10993     {
10994       itface = faceDomains.begin();
10995       for (; itface != faceDomains.end(); ++itface)
10996         {
10997           std::map<int, int> domvol = itface->second;
10998           if (!domvol.count(idomain))
10999             continue;
11000           DownIdType face = itface->first;
11001           //MESSAGE(" --- face " << face.cellId);
11002           std::set<int> oldNodes;
11003           oldNodes.clear();
11004           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11005           bool isMultipleDetected = false;
11006           std::set<int>::iterator itn = oldNodes.begin();
11007           for (; itn != oldNodes.end(); ++itn)
11008             {
11009               int oldId = *itn;
11010               //MESSAGE("     node " << oldId);
11011               if (!nodeDomains.count(oldId))
11012                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11013               if (nodeDomains[oldId].empty())
11014                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11015               std::map<int, int>::iterator itdom = domvol.begin();
11016               for (; itdom != domvol.end(); ++itdom)
11017                 {
11018                   int idom = itdom->first;
11019                   //MESSAGE("         domain " << idom);
11020                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
11021                     {
11022                       if (nodeDomains[oldId].size() >= 2) // a multiple node
11023                         {
11024                           vector<int> orderedDoms;
11025                           //MESSAGE("multiple node " << oldId);
11026                           isMultipleDetected =true;
11027                           if (mutipleNodes.count(oldId))
11028                             orderedDoms = mutipleNodes[oldId];
11029                           else
11030                             {
11031                               map<int,int>::iterator it = nodeDomains[oldId].begin();
11032                               for (; it != nodeDomains[oldId].end(); ++it)
11033                                 orderedDoms.push_back(it->first);
11034                             }
11035                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
11036                           //stringstream txt;
11037                           //for (int i=0; i<orderedDoms.size(); i++)
11038                           //  txt << orderedDoms[i] << " ";
11039                           //MESSAGE("orderedDoms " << txt.str());
11040                           mutipleNodes[oldId] = orderedDoms;
11041                         }
11042                       double *coords = grid->GetPoint(oldId);
11043                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11044                       int newId = newNode->getVtkId();
11045                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
11046                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11047                     }
11048                 }
11049             }
11050           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11051             {
11052               //MESSAGE("multiple Nodes detected on a shared face");
11053               int downId = itface->first.cellId;
11054               unsigned char cellType = itface->first.cellType;
11055               int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11056               const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11057               const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11058               for (int ie =0; ie < nbEdges; ie++)
11059                 {
11060                   int nodes[3];
11061                   int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11062                   if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11063                     {
11064                       vector<int> vn0 = mutipleNodes[nodes[0]];
11065                       vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11066                       sort( vn0.begin(), vn0.end() );
11067                       sort( vn1.begin(), vn1.end() );
11068                       if (vn0 == vn1)
11069                         {
11070                           //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11071                           double *coords = grid->GetPoint(nodes[0]);
11072                           gp_Pnt p0(coords[0], coords[1], coords[2]);
11073                           coords = grid->GetPoint(nodes[nbNodes - 1]);
11074                           gp_Pnt p1(coords[0], coords[1], coords[2]);
11075                           gp_Pnt gref;
11076                           int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11077                           map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11078                           map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11079                           int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11080                           for (int id=0; id < vn0.size(); id++)
11081                             {
11082                               int idom = vn0[id];
11083                               for (int ivol=0; ivol<nbvol; ivol++)
11084                                 {
11085                                   int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11086                                   SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11087                                   if (theElems[idom].count(elem))
11088                                     {
11089                                       SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11090                                       domvol[idom] = svol;
11091                                       //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11092                                       double values[3];
11093                                       vtkIdType npts = 0;
11094                                       vtkIdType* pts = 0;
11095                                       grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11096                                       SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11097                                       if (id ==0)
11098                                         {
11099                                           gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11100                                           angleDom[idom] = 0;
11101                                         }
11102                                       else
11103                                         {
11104                                           gp_Pnt g(values[0], values[1], values[2]);
11105                                           angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11106                                           //MESSAGE("  angle=" << angleDom[idom]);
11107                                         }
11108                                       break;
11109                                     }
11110                                 }
11111                             }
11112                           map<double, int> sortedDom; // sort domains by angle
11113                           for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11114                             sortedDom[ia->second] = ia->first;
11115                           vector<int> vnodes;
11116                           vector<int> vdom;
11117                           for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11118                             {
11119                               vdom.push_back(ib->second);
11120                               //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11121                             }
11122                           for (int ino = 0; ino < nbNodes; ino++)
11123                             vnodes.push_back(nodes[ino]);
11124                           edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11125                         }
11126                     }
11127                 }
11128             }
11129         }
11130     }
11131
11132   // --- iterate on shared faces (volumes to modify, face to extrude)
11133   //     get node id's of the face (id SMDS = id VTK)
11134   //     create flat element with old and new nodes if requested
11135
11136   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11137   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11138
11139   std::map<int, std::map<long,int> > nodeQuadDomains;
11140   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11141
11142   if (createJointElems)
11143     {
11144       itface = faceDomains.begin();
11145       for (; itface != faceDomains.end(); ++itface)
11146         {
11147           DownIdType face = itface->first;
11148           std::set<int> oldNodes;
11149           std::set<int>::iterator itn;
11150           oldNodes.clear();
11151           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11152
11153           std::map<int, int> domvol = itface->second;
11154           std::map<int, int>::iterator itdom = domvol.begin();
11155           int dom1 = itdom->first;
11156           int vtkVolId = itdom->second;
11157           itdom++;
11158           int dom2 = itdom->first;
11159           SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11160                                                              nodeQuadDomains);
11161           stringstream grpname;
11162           grpname << "j_";
11163           if (dom1 < dom2)
11164             grpname << dom1 << "_" << dom2;
11165           else
11166             grpname << dom2 << "_" << dom1;
11167           int idg;
11168           string namegrp = grpname.str();
11169           if (!mapOfJunctionGroups.count(namegrp))
11170             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11171           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11172           if (sgrp)
11173             sgrp->Add(vol->GetID());
11174         }
11175     }
11176
11177   // --- create volumes on multiple domain intersection if requested
11178   //     iterate on edgesMultiDomains
11179
11180   if (createJointElems)
11181     {
11182       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11183       for (; ite != edgesMultiDomains.end(); ++ite)
11184         {
11185           vector<int> nodes = ite->first;
11186           vector<int> orderDom = ite->second;
11187           vector<vtkIdType> orderedNodes;
11188           if (nodes.size() == 2)
11189             {
11190               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11191               for (int ino=0; ino < nodes.size(); ino++)
11192                 if (orderDom.size() == 3)
11193                   for (int idom = 0; idom <orderDom.size(); idom++)
11194                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11195                 else
11196                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11197                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11198               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11199
11200               stringstream grpname;
11201               grpname << "mj_";
11202               grpname << 0 << "_" << 0;
11203               int idg;
11204               string namegrp = grpname.str();
11205               if (!mapOfJunctionGroups.count(namegrp))
11206                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11207               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11208               if (sgrp)
11209                 sgrp->Add(vol->GetID());
11210             }
11211           else
11212             {
11213               // TODO quadratic nodes
11214             }
11215         }
11216     }
11217
11218   // --- list the explicit faces and edges of the mesh that need to be modified,
11219   //     i.e. faces and edges built with one or more duplicated nodes.
11220   //     associate these faces or edges to their corresponding domain.
11221   //     only the first domain found is kept when a face or edge is shared
11222
11223   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11224   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11225   faceOrEdgeDom.clear();
11226   feDom.clear();
11227
11228   for (int idomain = 0; idomain < theElems.size(); idomain++)
11229     {
11230       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11231       for (; itnod != nodeDomains.end(); ++itnod)
11232         {
11233           int oldId = itnod->first;
11234           //MESSAGE("     node " << oldId);
11235           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11236           for (int i = 0; i < l.ncells; i++)
11237             {
11238               int vtkId = l.cells[i];
11239               int vtkType = grid->GetCellType(vtkId);
11240               int downId = grid->CellIdToDownId(vtkId);
11241               DownIdType aCell(downId, vtkType);
11242               int volParents[1000];
11243               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11244               for (int j = 0; j < nbvol; j++)
11245                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11246                   if (!feDom.count(vtkId))
11247                     {
11248                       feDom[vtkId] = idomain;
11249                       faceOrEdgeDom[aCell] = emptyMap;
11250                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11251                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11252                       //        << " type " << vtkType << " downId " << downId);
11253                     }
11254             }
11255         }
11256     }
11257
11258   // --- iterate on shared faces (volumes to modify, face to extrude)
11259   //     get node id's of the face
11260   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11261
11262   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11263   for (int m=0; m<3; m++)
11264     {
11265       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11266       itface = (*amap).begin();
11267       for (; itface != (*amap).end(); ++itface)
11268         {
11269           DownIdType face = itface->first;
11270           std::set<int> oldNodes;
11271           std::set<int>::iterator itn;
11272           oldNodes.clear();
11273           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11274           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11275           std::map<int, int> localClonedNodeIds;
11276
11277           std::map<int, int> domvol = itface->second;
11278           std::map<int, int>::iterator itdom = domvol.begin();
11279           for (; itdom != domvol.end(); ++itdom)
11280             {
11281               int idom = itdom->first;
11282               int vtkVolId = itdom->second;
11283               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11284               localClonedNodeIds.clear();
11285               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11286                 {
11287                   int oldId = *itn;
11288                   if (nodeDomains[oldId].count(idom))
11289                     {
11290                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11291                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11292                     }
11293                 }
11294               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11295             }
11296         }
11297     }
11298
11299   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11300   grid->BuildLinks();
11301
11302   CHRONOSTOP(50);
11303   counters::stats();
11304   return true;
11305 }
11306
11307 /*!
11308  * \brief Double nodes on some external faces and create flat elements.
11309  * Flat elements are mainly used by some types of mechanic calculations.
11310  *
11311  * Each group of the list must be constituted of faces.
11312  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11313  * @param theElems - list of groups of faces, where a group of faces is a set of
11314  * SMDS_MeshElements sorted by Id.
11315  * @return TRUE if operation has been completed successfully, FALSE otherwise
11316  */
11317 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11318 {
11319   MESSAGE("-------------------------------------------------");
11320   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11321   MESSAGE("-------------------------------------------------");
11322
11323   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11324
11325   // --- For each group of faces
11326   //     duplicate the nodes, create a flat element based on the face
11327   //     replace the nodes of the faces by their clones
11328
11329   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11330   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11331   clonedNodes.clear();
11332   intermediateNodes.clear();
11333   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11334   mapOfJunctionGroups.clear();
11335
11336   for (int idom = 0; idom < theElems.size(); idom++)
11337     {
11338       const TIDSortedElemSet& domain = theElems[idom];
11339       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11340       for (; elemItr != domain.end(); ++elemItr)
11341         {
11342           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11343           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11344           if (!aFace)
11345             continue;
11346           // MESSAGE("aFace=" << aFace->GetID());
11347           bool isQuad = aFace->IsQuadratic();
11348           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11349
11350           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11351
11352           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11353           while (nodeIt->more())
11354             {
11355               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11356               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11357               if (isMedium)
11358                 ln2.push_back(node);
11359               else
11360                 ln0.push_back(node);
11361
11362               const SMDS_MeshNode* clone = 0;
11363               if (!clonedNodes.count(node))
11364                 {
11365                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11366                   clonedNodes[node] = clone;
11367                 }
11368               else
11369                 clone = clonedNodes[node];
11370
11371               if (isMedium)
11372                 ln3.push_back(clone);
11373               else
11374                 ln1.push_back(clone);
11375
11376               const SMDS_MeshNode* inter = 0;
11377               if (isQuad && (!isMedium))
11378                 {
11379                   if (!intermediateNodes.count(node))
11380                     {
11381                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11382                       intermediateNodes[node] = inter;
11383                     }
11384                   else
11385                     inter = intermediateNodes[node];
11386                   ln4.push_back(inter);
11387                 }
11388             }
11389
11390           // --- extrude the face
11391
11392           vector<const SMDS_MeshNode*> ln;
11393           SMDS_MeshVolume* vol = 0;
11394           vtkIdType aType = aFace->GetVtkType();
11395           switch (aType)
11396           {
11397             case VTK_TRIANGLE:
11398               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11399               // MESSAGE("vol prism " << vol->GetID());
11400               ln.push_back(ln1[0]);
11401               ln.push_back(ln1[1]);
11402               ln.push_back(ln1[2]);
11403               break;
11404             case VTK_QUAD:
11405               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11406               // MESSAGE("vol hexa " << vol->GetID());
11407               ln.push_back(ln1[0]);
11408               ln.push_back(ln1[1]);
11409               ln.push_back(ln1[2]);
11410               ln.push_back(ln1[3]);
11411               break;
11412             case VTK_QUADRATIC_TRIANGLE:
11413               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11414                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11415               // MESSAGE("vol quad prism " << vol->GetID());
11416               ln.push_back(ln1[0]);
11417               ln.push_back(ln1[1]);
11418               ln.push_back(ln1[2]);
11419               ln.push_back(ln3[0]);
11420               ln.push_back(ln3[1]);
11421               ln.push_back(ln3[2]);
11422               break;
11423             case VTK_QUADRATIC_QUAD:
11424 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11425 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11426 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11427               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11428                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11429                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11430               // MESSAGE("vol quad hexa " << vol->GetID());
11431               ln.push_back(ln1[0]);
11432               ln.push_back(ln1[1]);
11433               ln.push_back(ln1[2]);
11434               ln.push_back(ln1[3]);
11435               ln.push_back(ln3[0]);
11436               ln.push_back(ln3[1]);
11437               ln.push_back(ln3[2]);
11438               ln.push_back(ln3[3]);
11439               break;
11440             case VTK_POLYGON:
11441               break;
11442             default:
11443               break;
11444           }
11445
11446           if (vol)
11447             {
11448               stringstream grpname;
11449               grpname << "jf_";
11450               grpname << idom;
11451               int idg;
11452               string namegrp = grpname.str();
11453               if (!mapOfJunctionGroups.count(namegrp))
11454                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11455               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11456               if (sgrp)
11457                 sgrp->Add(vol->GetID());
11458             }
11459
11460           // --- modify the face
11461
11462           aFace->ChangeNodes(&ln[0], ln.size());
11463         }
11464     }
11465   return true;
11466 }
11467
11468 //================================================================================
11469 /*!
11470  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11471  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11472  * \return TRUE if operation has been completed successfully, FALSE otherwise
11473  */
11474 //================================================================================
11475
11476 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11477 {
11478   // iterates on volume elements and detect all free faces on them
11479   SMESHDS_Mesh* aMesh = GetMeshDS();
11480   if (!aMesh)
11481     return false;
11482   //bool res = false;
11483   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11484   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11485   while(vIt->more())
11486   {
11487     const SMDS_MeshVolume* volume = vIt->next();
11488     SMDS_VolumeTool vTool( volume );
11489     vTool.SetExternalNormal();
11490     const bool isPoly = volume->IsPoly();
11491     const bool isQuad = volume->IsQuadratic();
11492     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11493     {
11494       if (!vTool.IsFreeFace(iface))
11495         continue;
11496       nbFree++;
11497       vector<const SMDS_MeshNode *> nodes;
11498       int nbFaceNodes = vTool.NbFaceNodes(iface);
11499       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11500       int inode = 0;
11501       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11502         nodes.push_back(faceNodes[inode]);
11503       if (isQuad)
11504         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11505           nodes.push_back(faceNodes[inode]);
11506
11507       // add new face based on volume nodes
11508       if (aMesh->FindFace( nodes ) ) {
11509         nbExisted++;
11510         continue; // face already exsist
11511       }
11512       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11513       nbCreated++;
11514     }
11515   }
11516   return ( nbFree==(nbExisted+nbCreated) );
11517 }
11518
11519 namespace
11520 {
11521   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11522   {
11523     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11524       return n;
11525     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11526   }
11527 }
11528 //================================================================================
11529 /*!
11530  * \brief Creates missing boundary elements
11531  *  \param elements - elements whose boundary is to be checked
11532  *  \param dimension - defines type of boundary elements to create
11533  *  \param group - a group to store created boundary elements in
11534  *  \param targetMesh - a mesh to store created boundary elements in
11535  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11536  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
11537  *                                boundary elements will be copied into the targetMesh
11538  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11539  *                                boundary elements will be added into the new group
11540  *  \param aroundElements - if true, elements will be created on boundary of given
11541  *                          elements else, on boundary of the whole mesh. This
11542  *                          option works for 2D elements only.
11543  * \return nb of added boundary elements
11544  */
11545 //================================================================================
11546
11547 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11548                                        Bnd_Dimension           dimension,
11549                                        SMESH_Group*            group/*=0*/,
11550                                        SMESH_Mesh*             targetMesh/*=0*/,
11551                                        bool                    toCopyElements/*=false*/,
11552                                        bool                    toCopyExistingBondary/*=false*/,
11553                                        bool                    toAddExistingBondary/*= false*/,
11554                                        bool                    aroundElements/*= false*/)
11555 {
11556   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11557   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11558   // hope that all elements are of the same type, do not check them all
11559   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11560     throw SALOME_Exception(LOCALIZED("wrong element type"));
11561
11562   if ( aroundElements && elemType == SMDSAbs_Volume )
11563     throw SALOME_Exception(LOCALIZED("wrong element type for aroundElements==true"));
11564
11565   if ( !targetMesh )
11566     toCopyElements = toCopyExistingBondary = false;
11567
11568   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11569   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11570   int nbAddedBnd = 0;
11571
11572   // editor adding present bnd elements and optionally holding elements to add to the group
11573   SMESH_MeshEditor* presentEditor;
11574   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11575   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11576
11577   SMDS_VolumeTool vTool;
11578   TIDSortedElemSet avoidSet;
11579   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11580   int inode;
11581
11582   typedef vector<const SMDS_MeshNode*> TConnectivity;
11583
11584   SMDS_ElemIteratorPtr eIt;
11585   if (elements.empty())
11586     eIt = aMesh->elementsIterator(elemType);
11587   else
11588     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11589
11590   while (eIt->more())
11591   {
11592     const SMDS_MeshElement* elem = eIt->next();
11593     const int iQuad = elem->IsQuadratic();
11594
11595     // ------------------------------------------------------------------------------------
11596     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11597     // ------------------------------------------------------------------------------------
11598     vector<const SMDS_MeshElement*> presentBndElems;
11599     vector<TConnectivity>           missingBndElems;
11600     TConnectivity nodes;
11601     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11602     {
11603       vTool.SetExternalNormal();
11604       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11605       {
11606         if (!vTool.IsFreeFace(iface))
11607           continue;
11608         int nbFaceNodes = vTool.NbFaceNodes(iface);
11609         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11610         if ( missType == SMDSAbs_Edge ) // boundary edges
11611         {
11612           nodes.resize( 2+iQuad );
11613           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11614           {
11615             for ( int j = 0; j < nodes.size(); ++j )
11616               nodes[j] =nn[i+j];
11617             if ( const SMDS_MeshElement* edge =
11618                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11619               presentBndElems.push_back( edge );
11620             else
11621               missingBndElems.push_back( nodes );
11622           }
11623         }
11624         else // boundary face
11625         {
11626           nodes.clear();
11627           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11628             nodes.push_back( nn[inode] );
11629           if (iQuad)
11630             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11631               nodes.push_back( nn[inode] );
11632
11633           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11634             presentBndElems.push_back( f );
11635           else
11636             missingBndElems.push_back( nodes );
11637         }
11638       }
11639     }
11640     else                     // elem is a face ------------------------------------------
11641     {
11642       avoidSet.clear(), avoidSet.insert( elem );
11643       int nbNodes = elem->NbCornerNodes();
11644       nodes.resize( 2 /*+ iQuad*/);
11645       for ( int i = 0; i < nbNodes; i++ )
11646       {
11647         nodes[0] = elem->GetNode(i);
11648         nodes[1] = elem->GetNode((i+1)%nbNodes);
11649         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11650           continue; // not free link
11651
11652         //if ( iQuad )
11653         //nodes[2] = elem->GetNode( i + nbNodes );
11654         if ( const SMDS_MeshElement* edge =
11655              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11656           presentBndElems.push_back( edge );
11657         else
11658           missingBndElems.push_back( nodes );
11659       }
11660     }
11661
11662     // ---------------------------------
11663     // 2. Add missing boundary elements
11664     // ---------------------------------
11665     if ( targetMesh != myMesh )
11666       // instead of making a map of nodes in this mesh and targetMesh,
11667       // we create nodes with same IDs. We can renumber them later, if needed
11668       for ( int i = 0; i < missingBndElems.size(); ++i )
11669       {
11670         TConnectivity& srcNodes = missingBndElems[i];
11671         TConnectivity  nodes( srcNodes.size() );
11672         for ( inode = 0; inode < nodes.size(); ++inode )
11673           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11674         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11675                                                                    missType,
11676                                                                    /*noMedium=*/true))
11677           continue;
11678         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11679         ++nbAddedBnd;
11680       }
11681     else
11682       for ( int i = 0; i < missingBndElems.size(); ++i )
11683       {
11684         TConnectivity& nodes = missingBndElems[i];
11685         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11686                                                                    missType,
11687                                                                    /*noMedium=*/true))
11688           continue;
11689         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11690         ++nbAddedBnd;
11691       }
11692
11693     // ----------------------------------
11694     // 3. Copy present boundary elements
11695     // ----------------------------------
11696     if ( toCopyExistingBondary )
11697       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11698       {
11699         const SMDS_MeshElement* e = presentBndElems[i];
11700         TConnectivity nodes( e->NbNodes() );
11701         for ( inode = 0; inode < nodes.size(); ++inode )
11702           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11703         presentEditor->AddElement(nodes, missType, e->IsPoly());
11704       }
11705     else // store present elements to add them to a group
11706       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11707       {
11708         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11709       }
11710       
11711   } // loop on given elements
11712
11713   // ---------------------------------------------
11714   // 4. Fill group with boundary elements
11715   // ---------------------------------------------
11716   if ( group )
11717   {
11718     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11719       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11720         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11721   }
11722   tgtEditor.myLastCreatedElems.Clear();
11723   tgtEditor2.myLastCreatedElems.Clear();
11724
11725   // -----------------------
11726   // 5. Copy given elements
11727   // -----------------------
11728   if ( toCopyElements && targetMesh != myMesh )
11729   {
11730     if (elements.empty())
11731       eIt = aMesh->elementsIterator(elemType);
11732     else
11733       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11734     while (eIt->more())
11735     {
11736       const SMDS_MeshElement* elem = eIt->next();
11737       TConnectivity nodes( elem->NbNodes() );
11738       for ( inode = 0; inode < nodes.size(); ++inode )
11739         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11740       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11741
11742       tgtEditor.myLastCreatedElems.Clear();
11743     }
11744   }
11745   return nbAddedBnd;
11746 }