Salome HOME
fix regression of smesh/3D_mesh_Polyhedrons/A2
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 // Copyright (C) 2007-2011  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       if ( aBadRate1 <= aBadRate2 ) {
1136         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1137                                   aNodes[6], aNodes[7], newN );
1138         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1139                                   newN,      aNodes[4], aNodes[5] );
1140       }
1141       else {
1142         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1143                                   aNodes[7], aNodes[4], newN );
1144         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1145                                   newN,      aNodes[5], aNodes[6] );
1146       }
1147     } // quadratic case
1148
1149     // care of a new element
1150
1151     myLastCreatedElems.Append(newElem1);
1152     myLastCreatedElems.Append(newElem2);
1153     AddToSameGroups( newElem1, elem, aMesh );
1154     AddToSameGroups( newElem2, elem, aMesh );
1155
1156     // put a new triangle on the same shape
1157     if ( aShapeId )
1158       {
1159         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1160         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1161       }
1162     aMesh->RemoveElement( elem );
1163   }
1164   return true;
1165 }
1166
1167 //=======================================================================
1168 //function : BestSplit
1169 //purpose  : Find better diagonal for cutting.
1170 //=======================================================================
1171
1172 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1173                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1174 {
1175   myLastCreatedElems.Clear();
1176   myLastCreatedNodes.Clear();
1177
1178   if (!theCrit.get())
1179     return -1;
1180
1181   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1182     return -1;
1183
1184   if( theQuad->NbNodes()==4 ||
1185       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1186
1187     // retrieve element nodes
1188     const SMDS_MeshNode* aNodes [4];
1189     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1190     int i = 0;
1191     //while (itN->more())
1192     while (i<4) {
1193       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1194     }
1195     // compare two sets of possible triangles
1196     double aBadRate1, aBadRate2; // to what extent a set is bad
1197     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1198     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1199     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1200
1201     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1202     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1203     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1204
1205     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1206       return 1; // diagonal 1-3
1207
1208     return 2; // diagonal 2-4
1209   }
1210   return -1;
1211 }
1212
1213 namespace
1214 {
1215   // Methods of splitting volumes into tetra
1216
1217   const int theHexTo5_1[5*4+1] =
1218     {
1219       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1220     };
1221   const int theHexTo5_2[5*4+1] =
1222     {
1223       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1224     };
1225   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1226
1227   const int theHexTo6_1[6*4+1] =
1228     {
1229       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
1230     };
1231   const int theHexTo6_2[6*4+1] =
1232     {
1233       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
1234     };
1235   const int theHexTo6_3[6*4+1] =
1236     {
1237       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
1238     };
1239   const int theHexTo6_4[6*4+1] =
1240     {
1241       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
1242     };
1243   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1244
1245   const int thePyraTo2_1[2*4+1] =
1246     {
1247       0, 1, 2, 4,    0, 2, 3, 4,   -1
1248     };
1249   const int thePyraTo2_2[2*4+1] =
1250     {
1251       1, 2, 3, 4,    1, 3, 0, 4,   -1
1252     };
1253   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1254
1255   const int thePentaTo3_1[3*4+1] =
1256     {
1257       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1258     };
1259   const int thePentaTo3_2[3*4+1] =
1260     {
1261       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1262     };
1263   const int thePentaTo3_3[3*4+1] =
1264     {
1265       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1266     };
1267   const int thePentaTo3_4[3*4+1] =
1268     {
1269       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1270     };
1271   const int thePentaTo3_5[3*4+1] =
1272     {
1273       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1274     };
1275   const int thePentaTo3_6[3*4+1] =
1276     {
1277       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1278     };
1279   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1280                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1281
1282   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1283   {
1284     int _n1, _n2, _n3;
1285     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1286     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1287     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1288   };
1289   struct TSplitMethod
1290   {
1291     int        _nbTetra;
1292     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1293     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1294     bool       _ownConn;      //!< to delete _connectivity in destructor
1295     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1296
1297     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1298       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1299     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1300     bool hasFacet( const TTriangleFacet& facet ) const
1301     {
1302       const int* tetConn = _connectivity;
1303       for ( ; tetConn[0] >= 0; tetConn += 4 )
1304         if (( facet.contains( tetConn[0] ) +
1305               facet.contains( tetConn[1] ) +
1306               facet.contains( tetConn[2] ) +
1307               facet.contains( tetConn[3] )) == 3 )
1308           return true;
1309       return false;
1310     }
1311   };
1312
1313   //=======================================================================
1314   /*!
1315    * \brief return TSplitMethod for the given element
1316    */
1317   //=======================================================================
1318
1319   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1320   {
1321     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1322
1323     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1324     // an edge and a face barycenter; tertaherdons are based on triangles and
1325     // a volume barycenter
1326     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1327
1328     // Find out how adjacent volumes are split
1329
1330     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1331     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1332     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1333     {
1334       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1335       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1336       if ( nbNodes < 4 ) continue;
1337
1338       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1339       const int* nInd = vol.GetFaceNodesIndices( iF );
1340       if ( nbNodes == 4 )
1341       {
1342         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1343         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1344         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1345         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1346       }
1347       else
1348       {
1349         int iCom = 0; // common node of triangle faces to split into
1350         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1351         {
1352           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1353                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1354                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1355           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1356                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1357                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1358           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1359           {
1360             triaSplits.push_back( t012 );
1361             triaSplits.push_back( t023 );
1362             break;
1363           }
1364         }
1365       }
1366       if ( !triaSplits.empty() )
1367         hasAdjacentSplits = true;
1368     }
1369
1370     // Among variants of split method select one compliant with adjacent volumes
1371
1372     TSplitMethod method;
1373     if ( !vol.Element()->IsPoly() && !is24TetMode )
1374     {
1375       int nbVariants = 2, nbTet = 0;
1376       const int** connVariants = 0;
1377       switch ( vol.Element()->GetEntityType() )
1378       {
1379       case SMDSEntity_Hexa:
1380       case SMDSEntity_Quad_Hexa:
1381         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1382           connVariants = theHexTo5, nbTet = 5;
1383         else
1384           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1385         break;
1386       case SMDSEntity_Pyramid:
1387       case SMDSEntity_Quad_Pyramid:
1388         connVariants = thePyraTo2;  nbTet = 2;
1389         break;
1390       case SMDSEntity_Penta:
1391       case SMDSEntity_Quad_Penta:
1392         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1393         break;
1394       default:
1395         nbVariants = 0;
1396       }
1397       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1398       {
1399         // check method compliancy with adjacent tetras,
1400         // all found splits must be among facets of tetras described by this method
1401         method = TSplitMethod( nbTet, connVariants[variant] );
1402         if ( hasAdjacentSplits && method._nbTetra > 0 )
1403         {
1404           bool facetCreated = true;
1405           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1406           {
1407             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1408             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1409               facetCreated = method.hasFacet( *facet );
1410           }
1411           if ( !facetCreated )
1412             method = TSplitMethod(0); // incompatible method
1413         }
1414       }
1415     }
1416     if ( method._nbTetra < 1 )
1417     {
1418       // No standard method is applicable, use a generic solution:
1419       // each facet of a volume is split into triangles and
1420       // each of triangles and a volume barycenter form a tetrahedron.
1421
1422       int* connectivity = new int[ maxTetConnSize + 1 ];
1423       method._connectivity = connectivity;
1424       method._ownConn = true;
1425       method._baryNode = true;
1426
1427       int connSize = 0;
1428       int baryCenInd = vol.NbNodes();
1429       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1430       {
1431         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1432         const int*   nInd = vol.GetFaceNodesIndices( iF );
1433         // find common node of triangle facets of tetra to create
1434         int iCommon = 0; // index in linear numeration
1435         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1436         if ( !triaSplits.empty() )
1437         {
1438           // by found facets
1439           const TTriangleFacet* facet = &triaSplits.front();
1440           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1441             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1442                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1443               break;
1444         }
1445         else if ( nbNodes > 3 && !is24TetMode )
1446         {
1447           // find the best method of splitting into triangles by aspect ratio
1448           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1449           map< double, int > badness2iCommon;
1450           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1451           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1452           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1453             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1454             {
1455               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1456                                       nodes[ iQ*((iLast-1)%nbNodes)],
1457                                       nodes[ iQ*((iLast  )%nbNodes)]);
1458               double badness = getBadRate( &tria, aspectRatio );
1459               badness2iCommon.insert( make_pair( badness, iCommon ));
1460             }
1461           // use iCommon with lowest badness
1462           iCommon = badness2iCommon.begin()->second;
1463         }
1464         if ( iCommon >= nbNodes )
1465           iCommon = 0; // something wrong
1466
1467         // fill connectivity of tetrahedra based on a current face
1468         int nbTet = nbNodes - 2;
1469         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1470         {
1471           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1472           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1473           nbTet = nbNodes;
1474           for ( int i = 0; i < nbTet; ++i )
1475           {
1476             int i1 = i, i2 = (i+1) % nbNodes;
1477             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1478             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1479             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1480             connectivity[ connSize++ ] = faceBaryCenInd;
1481             connectivity[ connSize++ ] = baryCenInd;
1482           }
1483         }
1484         else
1485         {
1486           for ( int i = 0; i < nbTet; ++i )
1487           {
1488             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1489             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1490             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1491             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1492             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1493             connectivity[ connSize++ ] = baryCenInd;
1494           }
1495         }
1496         method._nbTetra += nbTet;
1497       }
1498       connectivity[ connSize++ ] = -1;
1499     }
1500     return method;
1501   }
1502   //================================================================================
1503   /*!
1504    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1505    */
1506   //================================================================================
1507
1508   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1509   {
1510     // find the tetrahedron including the three nodes of facet
1511     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1512     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1513     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1514     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1515     while ( volIt1->more() )
1516     {
1517       const SMDS_MeshElement* v = volIt1->next();
1518       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1519         continue;
1520       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1521       while ( volIt2->more() )
1522         if ( v != volIt2->next() )
1523           continue;
1524       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1525       while ( volIt3->more() )
1526         if ( v == volIt3->next() )
1527           return true;
1528     }
1529     return false;
1530   }
1531
1532   //=======================================================================
1533   /*!
1534    * \brief A key of a face of volume
1535    */
1536   //=======================================================================
1537
1538   struct TVolumeFaceKey: pair< int, pair< int, int> >
1539   {
1540     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1541     {
1542       TIDSortedNodeSet sortedNodes;
1543       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1544       int nbNodes = vol.NbFaceNodes( iF );
1545       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1546       for ( int i = 0; i < nbNodes; i += iQ )
1547         sortedNodes.insert( fNodes[i] );
1548       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1549       first = (*(n++))->GetID();
1550       second.first = (*(n++))->GetID();
1551       second.second = (*(n++))->GetID();
1552     }
1553   };
1554 } // namespace
1555
1556 //=======================================================================
1557 //function : SplitVolumesIntoTetra
1558 //purpose  : Split volumic elements into tetrahedra.
1559 //=======================================================================
1560
1561 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1562                                               const int                theMethodFlags)
1563 {
1564   // std-like iterator on coordinates of nodes of mesh element
1565   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1566   NXyzIterator xyzEnd;
1567
1568   SMDS_VolumeTool    volTool;
1569   SMESH_MesherHelper helper( *GetMesh());
1570
1571   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1572   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1573   
1574   SMESH_SequenceOfElemPtr newNodes, newElems;
1575
1576   // map face of volume to it's baricenrtic node
1577   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1578   double bc[3];
1579
1580   TIDSortedElemSet::const_iterator elem = theElems.begin();
1581   for ( ; elem != theElems.end(); ++elem )
1582   {
1583     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1584     if ( geomType <= SMDSEntity_Quad_Tetra )
1585       continue; // tetra or face or ...
1586
1587     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1588
1589     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1590     if ( splitMethod._nbTetra < 1 ) continue;
1591
1592     // find submesh to add new tetras to
1593     if ( !subMesh || !subMesh->Contains( *elem ))
1594     {
1595       int shapeID = FindShape( *elem );
1596       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1597       subMesh = GetMeshDS()->MeshElements( shapeID );
1598     }
1599     int iQ;
1600     if ( (*elem)->IsQuadratic() )
1601     {
1602       iQ = 2;
1603       // add quadratic links to the helper
1604       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1605       {
1606         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1607         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1608           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1609       }
1610       helper.SetIsQuadratic( true );
1611     }
1612     else
1613     {
1614       iQ = 1;
1615       helper.SetIsQuadratic( false );
1616     }
1617     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1618     helper.SetElementsOnShape( true );
1619     if ( splitMethod._baryNode )
1620     {
1621       // make a node at barycenter
1622       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1623       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1624       nodes.push_back( gcNode );
1625       newNodes.Append( gcNode );
1626     }
1627     if ( !splitMethod._faceBaryNode.empty() )
1628     {
1629       // make or find baricentric nodes of faces
1630       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1631       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1632       {
1633         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1634           volFace2BaryNode.insert
1635           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1636         if ( !f_n->second )
1637         {
1638           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1639           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1640         }
1641         nodes.push_back( iF_n->second = f_n->second );
1642       }
1643     }
1644
1645     // make tetras
1646     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1647     const int* tetConn = splitMethod._connectivity;
1648     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1649       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1650                                                        nodes[ tetConn[1] ],
1651                                                        nodes[ tetConn[2] ],
1652                                                        nodes[ tetConn[3] ]));
1653
1654     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1655
1656     // Split faces on sides of the split volume
1657
1658     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1659     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1660     {
1661       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1662       if ( nbNodes < 4 ) continue;
1663
1664       // find an existing face
1665       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1666                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1667       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1668       {
1669         // make triangles
1670         helper.SetElementsOnShape( false );
1671         vector< const SMDS_MeshElement* > triangles;
1672
1673         // find submesh to add new triangles in
1674         if ( !fSubMesh || !fSubMesh->Contains( face ))
1675         {
1676           int shapeID = FindShape( face );
1677           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1678         }
1679         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1680         if ( iF_n != splitMethod._faceBaryNode.end() )
1681         {
1682           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1683           {
1684             const SMDS_MeshNode* n1 = fNodes[iN];
1685             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1686             const SMDS_MeshNode *n3 = iF_n->second;
1687             if ( !volTool.IsFaceExternal( iF ))
1688               swap( n2, n3 );
1689             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1690
1691             if ( fSubMesh && n3->getshapeId() < 1 )
1692               fSubMesh->AddNode( n3 );
1693           }
1694         }
1695         else
1696         {
1697           // among possible triangles create ones discribed by split method
1698           const int* nInd = volTool.GetFaceNodesIndices( iF );
1699           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1700           int iCom = 0; // common node of triangle faces to split into
1701           list< TTriangleFacet > facets;
1702           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1703           {
1704             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1705                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1706                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1707             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1708                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1709                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1710             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1711             {
1712               facets.push_back( t012 );
1713               facets.push_back( t023 );
1714               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1715                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1716                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1717                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1718               break;
1719             }
1720           }
1721           list< TTriangleFacet >::iterator facet = facets.begin();
1722           for ( ; facet != facets.end(); ++facet )
1723           {
1724             if ( !volTool.IsFaceExternal( iF ))
1725               swap( facet->_n2, facet->_n3 );
1726             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1727                                                  volNodes[ facet->_n2 ],
1728                                                  volNodes[ facet->_n3 ]));
1729           }
1730         }
1731         for ( int i = 0; i < triangles.size(); ++i )
1732         {
1733           if ( !triangles[i] ) continue;
1734           if ( fSubMesh )
1735             fSubMesh->AddElement( triangles[i]);
1736           newElems.Append( triangles[i] );
1737         }
1738         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1739         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1740       }
1741
1742     } // loop on volume faces to split them into triangles
1743
1744     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1745
1746   } // loop on volumes to split
1747
1748   myLastCreatedNodes = newNodes;
1749   myLastCreatedElems = newElems;
1750 }
1751
1752 //=======================================================================
1753 //function : AddToSameGroups
1754 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1755 //=======================================================================
1756
1757 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1758                                         const SMDS_MeshElement* elemInGroups,
1759                                         SMESHDS_Mesh *          aMesh)
1760 {
1761   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1762   if (!groups.empty()) {
1763     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1764     for ( ; grIt != groups.end(); grIt++ ) {
1765       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1766       if ( group && group->Contains( elemInGroups ))
1767         group->SMDSGroup().Add( elemToAdd );
1768     }
1769   }
1770 }
1771
1772
1773 //=======================================================================
1774 //function : RemoveElemFromGroups
1775 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1776 //=======================================================================
1777 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1778                                              SMESHDS_Mesh *          aMesh)
1779 {
1780   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1781   if (!groups.empty())
1782   {
1783     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1784     for (; GrIt != groups.end(); GrIt++)
1785     {
1786       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1787       if (!grp || grp->IsEmpty()) continue;
1788       grp->SMDSGroup().Remove(removeelem);
1789     }
1790   }
1791 }
1792
1793 //================================================================================
1794 /*!
1795  * \brief Replace elemToRm by elemToAdd in the all groups
1796  */
1797 //================================================================================
1798
1799 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1800                                             const SMDS_MeshElement* elemToAdd,
1801                                             SMESHDS_Mesh *          aMesh)
1802 {
1803   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1804   if (!groups.empty()) {
1805     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1806     for ( ; grIt != groups.end(); grIt++ ) {
1807       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1808       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1809         group->SMDSGroup().Add( elemToAdd );
1810     }
1811   }
1812 }
1813
1814 //================================================================================
1815 /*!
1816  * \brief Replace elemToRm by elemToAdd in the all groups
1817  */
1818 //================================================================================
1819
1820 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1821                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1822                                             SMESHDS_Mesh *                         aMesh)
1823 {
1824   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1825   if (!groups.empty())
1826   {
1827     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1828     for ( ; grIt != groups.end(); grIt++ ) {
1829       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1830       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1831         for ( int i = 0; i < elemToAdd.size(); ++i )
1832           group->SMDSGroup().Add( elemToAdd[ i ] );
1833     }
1834   }
1835 }
1836
1837 //=======================================================================
1838 //function : QuadToTri
1839 //purpose  : Cut quadrangles into triangles.
1840 //           theCrit is used to select a diagonal to cut
1841 //=======================================================================
1842
1843 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1844                                   const bool         the13Diag)
1845 {
1846   myLastCreatedElems.Clear();
1847   myLastCreatedNodes.Clear();
1848
1849   MESSAGE( "::QuadToTri()" );
1850
1851   SMESHDS_Mesh * aMesh = GetMeshDS();
1852
1853   Handle(Geom_Surface) surface;
1854   SMESH_MesherHelper   helper( *GetMesh() );
1855
1856   TIDSortedElemSet::iterator itElem;
1857   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1858     const SMDS_MeshElement* elem = *itElem;
1859     if ( !elem || elem->GetType() != SMDSAbs_Face )
1860       continue;
1861     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1862     if(!isquad) continue;
1863
1864     if(elem->NbNodes()==4) {
1865       // retrieve element nodes
1866       const SMDS_MeshNode* aNodes [4];
1867       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1868       int i = 0;
1869       while ( itN->more() )
1870         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1871
1872       int aShapeId = FindShape( elem );
1873       const SMDS_MeshElement* newElem1 = 0;
1874       const SMDS_MeshElement* newElem2 = 0;
1875       if ( the13Diag ) {
1876         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1877         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1878       }
1879       else {
1880         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1881         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1882       }
1883       myLastCreatedElems.Append(newElem1);
1884       myLastCreatedElems.Append(newElem2);
1885       // put a new triangle on the same shape and add to the same groups
1886       if ( aShapeId )
1887         {
1888           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1889           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1890         }
1891       AddToSameGroups( newElem1, elem, aMesh );
1892       AddToSameGroups( newElem2, elem, aMesh );
1893       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1894       aMesh->RemoveElement( elem );
1895     }
1896
1897     // Quadratic quadrangle
1898
1899     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1900
1901       // get surface elem is on
1902       int aShapeId = FindShape( elem );
1903       if ( aShapeId != helper.GetSubShapeID() ) {
1904         surface.Nullify();
1905         TopoDS_Shape shape;
1906         if ( aShapeId > 0 )
1907           shape = aMesh->IndexToShape( aShapeId );
1908         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1909           TopoDS_Face face = TopoDS::Face( shape );
1910           surface = BRep_Tool::Surface( face );
1911           if ( !surface.IsNull() )
1912             helper.SetSubShape( shape );
1913         }
1914       }
1915
1916       const SMDS_MeshNode* aNodes [8];
1917       const SMDS_MeshNode* inFaceNode = 0;
1918       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1919       int i = 0;
1920       while ( itN->more() ) {
1921         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1922         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1923              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1924         {
1925           inFaceNode = aNodes[ i-1 ];
1926         }
1927       }
1928
1929       // find middle point for (0,1,2,3)
1930       // and create a node in this point;
1931       gp_XYZ p( 0,0,0 );
1932       if ( surface.IsNull() ) {
1933         for(i=0; i<4; i++)
1934           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1935         p /= 4;
1936       }
1937       else {
1938         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1939         gp_XY uv( 0,0 );
1940         for(i=0; i<4; i++)
1941           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1942         uv /= 4.;
1943         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1944       }
1945       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1946       myLastCreatedNodes.Append(newN);
1947
1948       // create a new element
1949       const SMDS_MeshElement* newElem1 = 0;
1950       const SMDS_MeshElement* newElem2 = 0;
1951       if ( the13Diag ) {
1952         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1953                                   aNodes[6], aNodes[7], newN );
1954         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1955                                   newN,      aNodes[4], aNodes[5] );
1956       }
1957       else {
1958         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1959                                   aNodes[7], aNodes[4], newN );
1960         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1961                                   newN,      aNodes[5], aNodes[6] );
1962       }
1963       myLastCreatedElems.Append(newElem1);
1964       myLastCreatedElems.Append(newElem2);
1965       // put a new triangle on the same shape and add to the same groups
1966       if ( aShapeId )
1967         {
1968           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1969           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1970         }
1971       AddToSameGroups( newElem1, elem, aMesh );
1972       AddToSameGroups( newElem2, elem, aMesh );
1973       aMesh->RemoveElement( elem );
1974     }
1975   }
1976
1977   return true;
1978 }
1979
1980 //=======================================================================
1981 //function : getAngle
1982 //purpose  :
1983 //=======================================================================
1984
1985 double getAngle(const SMDS_MeshElement * tr1,
1986                 const SMDS_MeshElement * tr2,
1987                 const SMDS_MeshNode *    n1,
1988                 const SMDS_MeshNode *    n2)
1989 {
1990   double angle = 2*PI; // bad angle
1991
1992   // get normals
1993   SMESH::Controls::TSequenceOfXYZ P1, P2;
1994   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1995        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1996     return angle;
1997   gp_Vec N1,N2;
1998   if(!tr1->IsQuadratic())
1999     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2000   else
2001     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2002   if ( N1.SquareMagnitude() <= gp::Resolution() )
2003     return angle;
2004   if(!tr2->IsQuadratic())
2005     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2006   else
2007     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2008   if ( N2.SquareMagnitude() <= gp::Resolution() )
2009     return angle;
2010
2011   // find the first diagonal node n1 in the triangles:
2012   // take in account a diagonal link orientation
2013   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2014   for ( int t = 0; t < 2; t++ ) {
2015     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2016     int i = 0, iDiag = -1;
2017     while ( it->more()) {
2018       const SMDS_MeshElement *n = it->next();
2019       if ( n == n1 || n == n2 ) {
2020         if ( iDiag < 0)
2021           iDiag = i;
2022         else {
2023           if ( i - iDiag == 1 )
2024             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2025           else
2026             nFirst[ t ] = n;
2027           break;
2028         }
2029       }
2030       i++;
2031     }
2032   }
2033   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2034     N2.Reverse();
2035
2036   angle = N1.Angle( N2 );
2037   //SCRUTE( angle );
2038   return angle;
2039 }
2040
2041 // =================================================
2042 // class generating a unique ID for a pair of nodes
2043 // and able to return nodes by that ID
2044 // =================================================
2045 class LinkID_Gen {
2046 public:
2047
2048   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2049     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2050   {}
2051
2052   long GetLinkID (const SMDS_MeshNode * n1,
2053                   const SMDS_MeshNode * n2) const
2054   {
2055     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2056   }
2057
2058   bool GetNodes (const long             theLinkID,
2059                  const SMDS_MeshNode* & theNode1,
2060                  const SMDS_MeshNode* & theNode2) const
2061   {
2062     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2063     if ( !theNode1 ) return false;
2064     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2065     if ( !theNode2 ) return false;
2066     return true;
2067   }
2068
2069 private:
2070   LinkID_Gen();
2071   const SMESHDS_Mesh* myMesh;
2072   long                myMaxID;
2073 };
2074
2075
2076 //=======================================================================
2077 //function : TriToQuad
2078 //purpose  : Fuse neighbour triangles into quadrangles.
2079 //           theCrit is used to select a neighbour to fuse with.
2080 //           theMaxAngle is a max angle between element normals at which
2081 //           fusion is still performed.
2082 //=======================================================================
2083
2084 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2085                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2086                                   const double                         theMaxAngle)
2087 {
2088   myLastCreatedElems.Clear();
2089   myLastCreatedNodes.Clear();
2090
2091   MESSAGE( "::TriToQuad()" );
2092
2093   if ( !theCrit.get() )
2094     return false;
2095
2096   SMESHDS_Mesh * aMesh = GetMeshDS();
2097
2098   // Prepare data for algo: build
2099   // 1. map of elements with their linkIDs
2100   // 2. map of linkIDs with their elements
2101
2102   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2103   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2104   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2105   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2106
2107   TIDSortedElemSet::iterator itElem;
2108   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2109     const SMDS_MeshElement* elem = *itElem;
2110     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2111     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2112     if(!IsTria) continue;
2113
2114     // retrieve element nodes
2115     const SMDS_MeshNode* aNodes [4];
2116     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2117     int i = 0;
2118     while ( i<3 )
2119       aNodes[ i++ ] = cast2Node( itN->next() );
2120     aNodes[ 3 ] = aNodes[ 0 ];
2121
2122     // fill maps
2123     for ( i = 0; i < 3; i++ ) {
2124       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2125       // check if elements sharing a link can be fused
2126       itLE = mapLi_listEl.find( link );
2127       if ( itLE != mapLi_listEl.end() ) {
2128         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2129           continue;
2130         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2131         //if ( FindShape( elem ) != FindShape( elem2 ))
2132         //  continue; // do not fuse triangles laying on different shapes
2133         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2134           continue; // avoid making badly shaped quads
2135         (*itLE).second.push_back( elem );
2136       }
2137       else {
2138         mapLi_listEl[ link ].push_back( elem );
2139       }
2140       mapEl_setLi [ elem ].insert( link );
2141     }
2142   }
2143   // Clean the maps from the links shared by a sole element, ie
2144   // links to which only one element is bound in mapLi_listEl
2145
2146   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2147     int nbElems = (*itLE).second.size();
2148     if ( nbElems < 2  ) {
2149       const SMDS_MeshElement* elem = (*itLE).second.front();
2150       SMESH_TLink link = (*itLE).first;
2151       mapEl_setLi[ elem ].erase( link );
2152       if ( mapEl_setLi[ elem ].empty() )
2153         mapEl_setLi.erase( elem );
2154     }
2155   }
2156
2157   // Algo: fuse triangles into quadrangles
2158
2159   while ( ! mapEl_setLi.empty() ) {
2160     // Look for the start element:
2161     // the element having the least nb of shared links
2162     const SMDS_MeshElement* startElem = 0;
2163     int minNbLinks = 4;
2164     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2165       int nbLinks = (*itEL).second.size();
2166       if ( nbLinks < minNbLinks ) {
2167         startElem = (*itEL).first;
2168         minNbLinks = nbLinks;
2169         if ( minNbLinks == 1 )
2170           break;
2171       }
2172     }
2173
2174     // search elements to fuse starting from startElem or links of elements
2175     // fused earlyer - startLinks
2176     list< SMESH_TLink > startLinks;
2177     while ( startElem || !startLinks.empty() ) {
2178       while ( !startElem && !startLinks.empty() ) {
2179         // Get an element to start, by a link
2180         SMESH_TLink linkId = startLinks.front();
2181         startLinks.pop_front();
2182         itLE = mapLi_listEl.find( linkId );
2183         if ( itLE != mapLi_listEl.end() ) {
2184           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2185           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2186           for ( ; itE != listElem.end() ; itE++ )
2187             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2188               startElem = (*itE);
2189           mapLi_listEl.erase( itLE );
2190         }
2191       }
2192
2193       if ( startElem ) {
2194         // Get candidates to be fused
2195         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2196         const SMESH_TLink *link12, *link13;
2197         startElem = 0;
2198         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2199         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2200         ASSERT( !setLi.empty() );
2201         set< SMESH_TLink >::iterator itLi;
2202         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2203         {
2204           const SMESH_TLink & link = (*itLi);
2205           itLE = mapLi_listEl.find( link );
2206           if ( itLE == mapLi_listEl.end() )
2207             continue;
2208
2209           const SMDS_MeshElement* elem = (*itLE).second.front();
2210           if ( elem == tr1 )
2211             elem = (*itLE).second.back();
2212           mapLi_listEl.erase( itLE );
2213           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2214             continue;
2215           if ( tr2 ) {
2216             tr3 = elem;
2217             link13 = &link;
2218           }
2219           else {
2220             tr2 = elem;
2221             link12 = &link;
2222           }
2223
2224           // add other links of elem to list of links to re-start from
2225           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2226           set< SMESH_TLink >::iterator it;
2227           for ( it = links.begin(); it != links.end(); it++ ) {
2228             const SMESH_TLink& link2 = (*it);
2229             if ( link2 != link )
2230               startLinks.push_back( link2 );
2231           }
2232         }
2233
2234         // Get nodes of possible quadrangles
2235         const SMDS_MeshNode *n12 [4], *n13 [4];
2236         bool Ok12 = false, Ok13 = false;
2237         const SMDS_MeshNode *linkNode1, *linkNode2;
2238         if(tr2) {
2239           linkNode1 = link12->first;
2240           linkNode2 = link12->second;
2241           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2242             Ok12 = true;
2243         }
2244         if(tr3) {
2245           linkNode1 = link13->first;
2246           linkNode2 = link13->second;
2247           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2248             Ok13 = true;
2249         }
2250
2251         // Choose a pair to fuse
2252         if ( Ok12 && Ok13 ) {
2253           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2254           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2255           double aBadRate12 = getBadRate( &quad12, theCrit );
2256           double aBadRate13 = getBadRate( &quad13, theCrit );
2257           if (  aBadRate13 < aBadRate12 )
2258             Ok12 = false;
2259           else
2260             Ok13 = false;
2261         }
2262
2263         // Make quadrangles
2264         // and remove fused elems and removed links from the maps
2265         mapEl_setLi.erase( tr1 );
2266         if ( Ok12 ) {
2267           mapEl_setLi.erase( tr2 );
2268           mapLi_listEl.erase( *link12 );
2269           if(tr1->NbNodes()==3) {
2270             const SMDS_MeshElement* newElem = 0;
2271             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2272             myLastCreatedElems.Append(newElem);
2273             AddToSameGroups( newElem, tr1, aMesh );
2274             int aShapeId = tr1->getshapeId();
2275             if ( aShapeId )
2276               {
2277                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2278               }
2279             aMesh->RemoveElement( tr1 );
2280             aMesh->RemoveElement( tr2 );
2281           }
2282           else {
2283             const SMDS_MeshNode* N1 [6];
2284             const SMDS_MeshNode* N2 [6];
2285             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2286             // now we receive following N1 and N2 (using numeration as above image)
2287             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2288             // i.e. first nodes from both arrays determ new diagonal
2289             const SMDS_MeshNode* aNodes[8];
2290             aNodes[0] = N1[0];
2291             aNodes[1] = N1[1];
2292             aNodes[2] = N2[0];
2293             aNodes[3] = N2[1];
2294             aNodes[4] = N1[3];
2295             aNodes[5] = N2[5];
2296             aNodes[6] = N2[3];
2297             aNodes[7] = N1[5];
2298             const SMDS_MeshElement* newElem = 0;
2299             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2300                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2301             myLastCreatedElems.Append(newElem);
2302             AddToSameGroups( newElem, tr1, aMesh );
2303             int aShapeId = tr1->getshapeId();
2304             if ( aShapeId )
2305               {
2306                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2307               }
2308             aMesh->RemoveElement( tr1 );
2309             aMesh->RemoveElement( tr2 );
2310             // remove middle node (9)
2311             GetMeshDS()->RemoveNode( N1[4] );
2312           }
2313         }
2314         else if ( Ok13 ) {
2315           mapEl_setLi.erase( tr3 );
2316           mapLi_listEl.erase( *link13 );
2317           if(tr1->NbNodes()==3) {
2318             const SMDS_MeshElement* newElem = 0;
2319             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2320             myLastCreatedElems.Append(newElem);
2321             AddToSameGroups( newElem, tr1, aMesh );
2322             int aShapeId = tr1->getshapeId();
2323             if ( aShapeId )
2324               {
2325                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2326               }
2327             aMesh->RemoveElement( tr1 );
2328             aMesh->RemoveElement( tr3 );
2329           }
2330           else {
2331             const SMDS_MeshNode* N1 [6];
2332             const SMDS_MeshNode* N2 [6];
2333             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2334             // now we receive following N1 and N2 (using numeration as above image)
2335             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2336             // i.e. first nodes from both arrays determ new diagonal
2337             const SMDS_MeshNode* aNodes[8];
2338             aNodes[0] = N1[0];
2339             aNodes[1] = N1[1];
2340             aNodes[2] = N2[0];
2341             aNodes[3] = N2[1];
2342             aNodes[4] = N1[3];
2343             aNodes[5] = N2[5];
2344             aNodes[6] = N2[3];
2345             aNodes[7] = N1[5];
2346             const SMDS_MeshElement* newElem = 0;
2347             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2348                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2349             myLastCreatedElems.Append(newElem);
2350             AddToSameGroups( newElem, tr1, aMesh );
2351             int aShapeId = tr1->getshapeId();
2352             if ( aShapeId )
2353               {
2354                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2355               }
2356             aMesh->RemoveElement( tr1 );
2357             aMesh->RemoveElement( tr3 );
2358             // remove middle node (9)
2359             GetMeshDS()->RemoveNode( N1[4] );
2360           }
2361         }
2362
2363         // Next element to fuse: the rejected one
2364         if ( tr3 )
2365           startElem = Ok12 ? tr3 : tr2;
2366
2367       } // if ( startElem )
2368     } // while ( startElem || !startLinks.empty() )
2369   } // while ( ! mapEl_setLi.empty() )
2370
2371   return true;
2372 }
2373
2374
2375 /*#define DUMPSO(txt) \
2376 //  cout << txt << endl;
2377 //=============================================================================
2378 //
2379 //
2380 //
2381 //=============================================================================
2382 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2383 {
2384 if ( i1 == i2 )
2385 return;
2386 int tmp = idNodes[ i1 ];
2387 idNodes[ i1 ] = idNodes[ i2 ];
2388 idNodes[ i2 ] = tmp;
2389 gp_Pnt Ptmp = P[ i1 ];
2390 P[ i1 ] = P[ i2 ];
2391 P[ i2 ] = Ptmp;
2392 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2393 }
2394
2395 //=======================================================================
2396 //function : SortQuadNodes
2397 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2398 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2399 //           1 or 2 else 0.
2400 //=======================================================================
2401
2402 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2403 int               idNodes[] )
2404 {
2405   gp_Pnt P[4];
2406   int i;
2407   for ( i = 0; i < 4; i++ ) {
2408     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2409     if ( !n ) return 0;
2410     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2411   }
2412
2413   gp_Vec V1(P[0], P[1]);
2414   gp_Vec V2(P[0], P[2]);
2415   gp_Vec V3(P[0], P[3]);
2416
2417   gp_Vec Cross1 = V1 ^ V2;
2418   gp_Vec Cross2 = V2 ^ V3;
2419
2420   i = 0;
2421   if (Cross1.Dot(Cross2) < 0)
2422   {
2423     Cross1 = V2 ^ V1;
2424     Cross2 = V1 ^ V3;
2425
2426     if (Cross1.Dot(Cross2) < 0)
2427       i = 2;
2428     else
2429       i = 1;
2430     swap ( i, i + 1, idNodes, P );
2431
2432     //     for ( int ii = 0; ii < 4; ii++ ) {
2433     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2434     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2435     //     }
2436   }
2437   return i;
2438 }
2439
2440 //=======================================================================
2441 //function : SortHexaNodes
2442 //purpose  : Set 8 nodes of a hexahedron in a good order.
2443 //           Return success status
2444 //=======================================================================
2445
2446 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2447                                       int               idNodes[] )
2448 {
2449   gp_Pnt P[8];
2450   int i;
2451   DUMPSO( "INPUT: ========================================");
2452   for ( i = 0; i < 8; i++ ) {
2453     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2454     if ( !n ) return false;
2455     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2456     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2457   }
2458   DUMPSO( "========================================");
2459
2460
2461   set<int> faceNodes;  // ids of bottom face nodes, to be found
2462   set<int> checkedId1; // ids of tried 2-nd nodes
2463   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2464   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2465   int iMin, iLoop1 = 0;
2466
2467   // Loop to try the 2-nd nodes
2468
2469   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2470   {
2471     // Find not checked 2-nd node
2472     for ( i = 1; i < 8; i++ )
2473       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2474         int id1 = idNodes[i];
2475         swap ( 1, i, idNodes, P );
2476         checkedId1.insert ( id1 );
2477         break;
2478       }
2479
2480     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2481     // ie that all but meybe one (id3 which is on the same face) nodes
2482     // lay on the same side from the triangle plane.
2483
2484     bool manyInPlane = false; // more than 4 nodes lay in plane
2485     int iLoop2 = 0;
2486     while ( ++iLoop2 < 6 ) {
2487
2488       // get 1-2-3 plane coeffs
2489       Standard_Real A, B, C, D;
2490       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2491       if ( N.SquareMagnitude() > gp::Resolution() )
2492       {
2493         gp_Pln pln ( P[0], N );
2494         pln.Coefficients( A, B, C, D );
2495
2496         // find the node (iMin) closest to pln
2497         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2498         set<int> idInPln;
2499         for ( i = 3; i < 8; i++ ) {
2500           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2501           if ( fabs( dist[i] ) < minDist ) {
2502             minDist = fabs( dist[i] );
2503             iMin = i;
2504           }
2505           if ( fabs( dist[i] ) <= tol )
2506             idInPln.insert( idNodes[i] );
2507         }
2508
2509         // there should not be more than 4 nodes in bottom plane
2510         if ( idInPln.size() > 1 )
2511         {
2512           DUMPSO( "### idInPln.size() = " << idInPln.size());
2513           // idInPlane does not contain the first 3 nodes
2514           if ( manyInPlane || idInPln.size() == 5)
2515             return false; // all nodes in one plane
2516           manyInPlane = true;
2517
2518           // set the 1-st node to be not in plane
2519           for ( i = 3; i < 8; i++ ) {
2520             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2521               DUMPSO( "### Reset 0-th node");
2522               swap( 0, i, idNodes, P );
2523               break;
2524             }
2525           }
2526
2527           // reset to re-check second nodes
2528           leastDist = DBL_MAX;
2529           faceNodes.clear();
2530           checkedId1.clear();
2531           iLoop1 = 0;
2532           break; // from iLoop2;
2533         }
2534
2535         // check that the other 4 nodes are on the same side
2536         bool sameSide = true;
2537         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2538         for ( i = 3; sameSide && i < 8; i++ ) {
2539           if ( i != iMin )
2540             sameSide = ( isNeg == dist[i] <= 0.);
2541         }
2542
2543         // keep best solution
2544         if ( sameSide && minDist < leastDist ) {
2545           leastDist = minDist;
2546           faceNodes.clear();
2547           faceNodes.insert( idNodes[ 1 ] );
2548           faceNodes.insert( idNodes[ 2 ] );
2549           faceNodes.insert( idNodes[ iMin ] );
2550           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2551                   << " leastDist = " << leastDist);
2552           if ( leastDist <= DBL_MIN )
2553             break;
2554         }
2555       }
2556
2557       // set next 3-d node to check
2558       int iNext = 2 + iLoop2;
2559       if ( iNext < 8 ) {
2560         DUMPSO( "Try 2-nd");
2561         swap ( 2, iNext, idNodes, P );
2562       }
2563     } // while ( iLoop2 < 6 )
2564   } // iLoop1
2565
2566   if ( faceNodes.empty() ) return false;
2567
2568   // Put the faceNodes in proper places
2569   for ( i = 4; i < 8; i++ ) {
2570     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2571       // find a place to put
2572       int iTo = 1;
2573       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2574         iTo++;
2575       DUMPSO( "Set faceNodes");
2576       swap ( iTo, i, idNodes, P );
2577     }
2578   }
2579
2580
2581   // Set nodes of the found bottom face in good order
2582   DUMPSO( " Found bottom face: ");
2583   i = SortQuadNodes( theMesh, idNodes );
2584   if ( i ) {
2585     gp_Pnt Ptmp = P[ i ];
2586     P[ i ] = P[ i+1 ];
2587     P[ i+1 ] = Ptmp;
2588   }
2589   //   else
2590   //     for ( int ii = 0; ii < 4; ii++ ) {
2591   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2592   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2593   //    }
2594
2595   // Gravity center of the top and bottom faces
2596   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2597   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2598
2599   // Get direction from the bottom to the top face
2600   gp_Vec upDir ( aGCb, aGCt );
2601   Standard_Real upDirSize = upDir.Magnitude();
2602   if ( upDirSize <= gp::Resolution() ) return false;
2603   upDir / upDirSize;
2604
2605   // Assure that the bottom face normal points up
2606   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2607   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2608   if ( Nb.Dot( upDir ) < 0 ) {
2609     DUMPSO( "Reverse bottom face");
2610     swap( 1, 3, idNodes, P );
2611   }
2612
2613   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2614   Standard_Real minDist = DBL_MAX;
2615   for ( i = 4; i < 8; i++ ) {
2616     // projection of P[i] to the plane defined by P[0] and upDir
2617     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2618     Standard_Real sqDist = P[0].SquareDistance( Pp );
2619     if ( sqDist < minDist ) {
2620       minDist = sqDist;
2621       iMin = i;
2622     }
2623   }
2624   DUMPSO( "Set 4-th");
2625   swap ( 4, iMin, idNodes, P );
2626
2627   // Set nodes of the top face in good order
2628   DUMPSO( "Sort top face");
2629   i = SortQuadNodes( theMesh, &idNodes[4] );
2630   if ( i ) {
2631     i += 4;
2632     gp_Pnt Ptmp = P[ i ];
2633     P[ i ] = P[ i+1 ];
2634     P[ i+1 ] = Ptmp;
2635   }
2636
2637   // Assure that direction of the top face normal is from the bottom face
2638   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2639   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2640   if ( Nt.Dot( upDir ) < 0 ) {
2641     DUMPSO( "Reverse top face");
2642     swap( 5, 7, idNodes, P );
2643   }
2644
2645   //   DUMPSO( "OUTPUT: ========================================");
2646   //   for ( i = 0; i < 8; i++ ) {
2647   //     float *p = ugrid->GetPoint(idNodes[i]);
2648   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2649   //   }
2650
2651   return true;
2652 }*/
2653
2654 //================================================================================
2655 /*!
2656  * \brief Return nodes linked to the given one
2657  * \param theNode - the node
2658  * \param linkedNodes - the found nodes
2659  * \param type - the type of elements to check
2660  *
2661  * Medium nodes are ignored
2662  */
2663 //================================================================================
2664
2665 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2666                                        TIDSortedElemSet &   linkedNodes,
2667                                        SMDSAbs_ElementType  type )
2668 {
2669   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2670   while ( elemIt->more() )
2671   {
2672     const SMDS_MeshElement* elem = elemIt->next();
2673     if(elem->GetType() == SMDSAbs_0DElement)
2674       continue;
2675     
2676     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2677     if ( elem->GetType() == SMDSAbs_Volume )
2678     {
2679       SMDS_VolumeTool vol( elem );
2680       while ( nodeIt->more() ) {
2681         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2682         if ( theNode != n && vol.IsLinked( theNode, n ))
2683           linkedNodes.insert( n );
2684       }
2685     }
2686     else
2687     {
2688       for ( int i = 0; nodeIt->more(); ++i ) {
2689         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2690         if ( n == theNode ) {
2691           int iBefore = i - 1;
2692           int iAfter  = i + 1;
2693           if ( elem->IsQuadratic() ) {
2694             int nb = elem->NbNodes() / 2;
2695             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2696             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2697           }
2698           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2699           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2700         }
2701       }
2702     }
2703   }
2704 }
2705
2706 //=======================================================================
2707 //function : laplacianSmooth
2708 //purpose  : pulls theNode toward the center of surrounding nodes directly
2709 //           connected to that node along an element edge
2710 //=======================================================================
2711
2712 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2713                      const Handle(Geom_Surface)&          theSurface,
2714                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2715 {
2716   // find surrounding nodes
2717
2718   TIDSortedElemSet nodeSet;
2719   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2720
2721   // compute new coodrs
2722
2723   double coord[] = { 0., 0., 0. };
2724   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2725   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2726     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2727     if ( theSurface.IsNull() ) { // smooth in 3D
2728       coord[0] += node->X();
2729       coord[1] += node->Y();
2730       coord[2] += node->Z();
2731     }
2732     else { // smooth in 2D
2733       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2734       gp_XY* uv = theUVMap[ node ];
2735       coord[0] += uv->X();
2736       coord[1] += uv->Y();
2737     }
2738   }
2739   int nbNodes = nodeSet.size();
2740   if ( !nbNodes )
2741     return;
2742   coord[0] /= nbNodes;
2743   coord[1] /= nbNodes;
2744
2745   if ( !theSurface.IsNull() ) {
2746     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2747     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2748     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2749     coord[0] = p3d.X();
2750     coord[1] = p3d.Y();
2751     coord[2] = p3d.Z();
2752   }
2753   else
2754     coord[2] /= nbNodes;
2755
2756   // move node
2757
2758   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2759 }
2760
2761 //=======================================================================
2762 //function : centroidalSmooth
2763 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2764 //           surrounding elements
2765 //=======================================================================
2766
2767 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2768                       const Handle(Geom_Surface)&          theSurface,
2769                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2770 {
2771   gp_XYZ aNewXYZ(0.,0.,0.);
2772   SMESH::Controls::Area anAreaFunc;
2773   double totalArea = 0.;
2774   int nbElems = 0;
2775
2776   // compute new XYZ
2777
2778   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2779   while ( elemIt->more() )
2780   {
2781     const SMDS_MeshElement* elem = elemIt->next();
2782     nbElems++;
2783
2784     gp_XYZ elemCenter(0.,0.,0.);
2785     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2786     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2787     int nn = elem->NbNodes();
2788     if(elem->IsQuadratic()) nn = nn/2;
2789     int i=0;
2790     //while ( itN->more() ) {
2791     while ( i<nn ) {
2792       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2793       i++;
2794       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2795       aNodePoints.push_back( aP );
2796       if ( !theSurface.IsNull() ) { // smooth in 2D
2797         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2798         gp_XY* uv = theUVMap[ aNode ];
2799         aP.SetCoord( uv->X(), uv->Y(), 0. );
2800       }
2801       elemCenter += aP;
2802     }
2803     double elemArea = anAreaFunc.GetValue( aNodePoints );
2804     totalArea += elemArea;
2805     elemCenter /= nn;
2806     aNewXYZ += elemCenter * elemArea;
2807   }
2808   aNewXYZ /= totalArea;
2809   if ( !theSurface.IsNull() ) {
2810     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2811     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2812   }
2813
2814   // move node
2815
2816   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2817 }
2818
2819 //=======================================================================
2820 //function : getClosestUV
2821 //purpose  : return UV of closest projection
2822 //=======================================================================
2823
2824 static bool getClosestUV (Extrema_GenExtPS& projector,
2825                           const gp_Pnt&     point,
2826                           gp_XY &           result)
2827 {
2828   projector.Perform( point );
2829   if ( projector.IsDone() ) {
2830     double u, v, minVal = DBL_MAX;
2831     for ( int i = projector.NbExt(); i > 0; i-- )
2832       if ( projector.Value( i ) < minVal ) {
2833         minVal = projector.Value( i );
2834         projector.Point( i ).Parameter( u, v );
2835       }
2836     result.SetCoord( u, v );
2837     return true;
2838   }
2839   return false;
2840 }
2841
2842 //=======================================================================
2843 //function : Smooth
2844 //purpose  : Smooth theElements during theNbIterations or until a worst
2845 //           element has aspect ratio <= theTgtAspectRatio.
2846 //           Aspect Ratio varies in range [1.0, inf].
2847 //           If theElements is empty, the whole mesh is smoothed.
2848 //           theFixedNodes contains additionally fixed nodes. Nodes built
2849 //           on edges and boundary nodes are always fixed.
2850 //=======================================================================
2851
2852 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2853                                set<const SMDS_MeshNode*> & theFixedNodes,
2854                                const SmoothMethod          theSmoothMethod,
2855                                const int                   theNbIterations,
2856                                double                      theTgtAspectRatio,
2857                                const bool                  the2D)
2858 {
2859   myLastCreatedElems.Clear();
2860   myLastCreatedNodes.Clear();
2861
2862   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2863
2864   if ( theTgtAspectRatio < 1.0 )
2865     theTgtAspectRatio = 1.0;
2866
2867   const double disttol = 1.e-16;
2868
2869   SMESH::Controls::AspectRatio aQualityFunc;
2870
2871   SMESHDS_Mesh* aMesh = GetMeshDS();
2872
2873   if ( theElems.empty() ) {
2874     // add all faces to theElems
2875     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2876     while ( fIt->more() ) {
2877       const SMDS_MeshElement* face = fIt->next();
2878       theElems.insert( face );
2879     }
2880   }
2881   // get all face ids theElems are on
2882   set< int > faceIdSet;
2883   TIDSortedElemSet::iterator itElem;
2884   if ( the2D )
2885     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2886       int fId = FindShape( *itElem );
2887       // check that corresponding submesh exists and a shape is face
2888       if (fId &&
2889           faceIdSet.find( fId ) == faceIdSet.end() &&
2890           aMesh->MeshElements( fId )) {
2891         TopoDS_Shape F = aMesh->IndexToShape( fId );
2892         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2893           faceIdSet.insert( fId );
2894       }
2895     }
2896   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2897
2898   // ===============================================
2899   // smooth elements on each TopoDS_Face separately
2900   // ===============================================
2901
2902   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2903   for ( ; fId != faceIdSet.rend(); ++fId ) {
2904     // get face surface and submesh
2905     Handle(Geom_Surface) surface;
2906     SMESHDS_SubMesh* faceSubMesh = 0;
2907     TopoDS_Face face;
2908     double fToler2 = 0, f,l;
2909     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2910     bool isUPeriodic = false, isVPeriodic = false;
2911     if ( *fId ) {
2912       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2913       surface = BRep_Tool::Surface( face );
2914       faceSubMesh = aMesh->MeshElements( *fId );
2915       fToler2 = BRep_Tool::Tolerance( face );
2916       fToler2 *= fToler2 * 10.;
2917       isUPeriodic = surface->IsUPeriodic();
2918       if ( isUPeriodic )
2919         surface->UPeriod();
2920       isVPeriodic = surface->IsVPeriodic();
2921       if ( isVPeriodic )
2922         surface->VPeriod();
2923       surface->Bounds( u1, u2, v1, v2 );
2924     }
2925     // ---------------------------------------------------------
2926     // for elements on a face, find movable and fixed nodes and
2927     // compute UV for them
2928     // ---------------------------------------------------------
2929     bool checkBoundaryNodes = false;
2930     bool isQuadratic = false;
2931     set<const SMDS_MeshNode*> setMovableNodes;
2932     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2933     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2934     list< const SMDS_MeshElement* > elemsOnFace;
2935
2936     Extrema_GenExtPS projector;
2937     GeomAdaptor_Surface surfAdaptor;
2938     if ( !surface.IsNull() ) {
2939       surfAdaptor.Load( surface );
2940       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2941     }
2942     int nbElemOnFace = 0;
2943     itElem = theElems.begin();
2944     // loop on not yet smoothed elements: look for elems on a face
2945     while ( itElem != theElems.end() ) {
2946       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2947         break; // all elements found
2948
2949       const SMDS_MeshElement* elem = *itElem;
2950       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2951            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2952         ++itElem;
2953         continue;
2954       }
2955       elemsOnFace.push_back( elem );
2956       theElems.erase( itElem++ );
2957       nbElemOnFace++;
2958
2959       if ( !isQuadratic )
2960         isQuadratic = elem->IsQuadratic();
2961
2962       // get movable nodes of elem
2963       const SMDS_MeshNode* node;
2964       SMDS_TypeOfPosition posType;
2965       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2966       int nn = 0, nbn =  elem->NbNodes();
2967       if(elem->IsQuadratic())
2968         nbn = nbn/2;
2969       while ( nn++ < nbn ) {
2970         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2971         const SMDS_PositionPtr& pos = node->GetPosition();
2972         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2973         if (posType != SMDS_TOP_EDGE &&
2974             posType != SMDS_TOP_VERTEX &&
2975             theFixedNodes.find( node ) == theFixedNodes.end())
2976         {
2977           // check if all faces around the node are on faceSubMesh
2978           // because a node on edge may be bound to face
2979           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2980           bool all = true;
2981           if ( faceSubMesh ) {
2982             while ( eIt->more() && all ) {
2983               const SMDS_MeshElement* e = eIt->next();
2984               all = faceSubMesh->Contains( e );
2985             }
2986           }
2987           if ( all )
2988             setMovableNodes.insert( node );
2989           else
2990             checkBoundaryNodes = true;
2991         }
2992         if ( posType == SMDS_TOP_3DSPACE )
2993           checkBoundaryNodes = true;
2994       }
2995
2996       if ( surface.IsNull() )
2997         continue;
2998
2999       // get nodes to check UV
3000       list< const SMDS_MeshNode* > uvCheckNodes;
3001       itN = elem->nodesIterator();
3002       nn = 0; nbn =  elem->NbNodes();
3003       if(elem->IsQuadratic())
3004         nbn = nbn/2;
3005       while ( nn++ < nbn ) {
3006         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3007         if ( uvMap.find( node ) == uvMap.end() )
3008           uvCheckNodes.push_back( node );
3009         // add nodes of elems sharing node
3010         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3011         //         while ( eIt->more() ) {
3012         //           const SMDS_MeshElement* e = eIt->next();
3013         //           if ( e != elem ) {
3014         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3015         //             while ( nIt->more() ) {
3016         //               const SMDS_MeshNode* n =
3017         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3018         //               if ( uvMap.find( n ) == uvMap.end() )
3019         //                 uvCheckNodes.push_back( n );
3020         //             }
3021         //           }
3022         //         }
3023       }
3024       // check UV on face
3025       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3026       for ( ; n != uvCheckNodes.end(); ++n ) {
3027         node = *n;
3028         gp_XY uv( 0, 0 );
3029         const SMDS_PositionPtr& pos = node->GetPosition();
3030         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3031         // get existing UV
3032         switch ( posType ) {
3033         case SMDS_TOP_FACE: {
3034           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3035           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3036           break;
3037         }
3038         case SMDS_TOP_EDGE: {
3039           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3040           Handle(Geom2d_Curve) pcurve;
3041           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3042             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3043           if ( !pcurve.IsNull() ) {
3044             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3045             uv = pcurve->Value( u ).XY();
3046           }
3047           break;
3048         }
3049         case SMDS_TOP_VERTEX: {
3050           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3051           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3052             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3053           break;
3054         }
3055         default:;
3056         }
3057         // check existing UV
3058         bool project = true;
3059         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3060         double dist1 = DBL_MAX, dist2 = 0;
3061         if ( posType != SMDS_TOP_3DSPACE ) {
3062           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3063           project = dist1 > fToler2;
3064         }
3065         if ( project ) { // compute new UV
3066           gp_XY newUV;
3067           if ( !getClosestUV( projector, pNode, newUV )) {
3068             MESSAGE("Node Projection Failed " << node);
3069           }
3070           else {
3071             if ( isUPeriodic )
3072               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3073             if ( isVPeriodic )
3074               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3075             // check new UV
3076             if ( posType != SMDS_TOP_3DSPACE )
3077               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3078             if ( dist2 < dist1 )
3079               uv = newUV;
3080           }
3081         }
3082         // store UV in the map
3083         listUV.push_back( uv );
3084         uvMap.insert( make_pair( node, &listUV.back() ));
3085       }
3086     } // loop on not yet smoothed elements
3087
3088     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3089       checkBoundaryNodes = true;
3090
3091     // fix nodes on mesh boundary
3092
3093     if ( checkBoundaryNodes ) {
3094       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3095       map< SMESH_TLink, int >::iterator link_nb;
3096       // put all elements links to linkNbMap
3097       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3098       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3099         const SMDS_MeshElement* elem = (*elemIt);
3100         int nbn =  elem->NbCornerNodes();
3101         // loop on elem links: insert them in linkNbMap
3102         for ( int iN = 0; iN < nbn; ++iN ) {
3103           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3104           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3105           SMESH_TLink link( n1, n2 );
3106           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3107           link_nb->second++;
3108         }
3109       }
3110       // remove nodes that are in links encountered only once from setMovableNodes
3111       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3112         if ( link_nb->second == 1 ) {
3113           setMovableNodes.erase( link_nb->first.node1() );
3114           setMovableNodes.erase( link_nb->first.node2() );
3115         }
3116       }
3117     }
3118
3119     // -----------------------------------------------------
3120     // for nodes on seam edge, compute one more UV ( uvMap2 );
3121     // find movable nodes linked to nodes on seam and which
3122     // are to be smoothed using the second UV ( uvMap2 )
3123     // -----------------------------------------------------
3124
3125     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3126     if ( !surface.IsNull() ) {
3127       TopExp_Explorer eExp( face, TopAbs_EDGE );
3128       for ( ; eExp.More(); eExp.Next() ) {
3129         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3130         if ( !BRep_Tool::IsClosed( edge, face ))
3131           continue;
3132         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3133         if ( !sm ) continue;
3134         // find out which parameter varies for a node on seam
3135         double f,l;
3136         gp_Pnt2d uv1, uv2;
3137         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3138         if ( pcurve.IsNull() ) continue;
3139         uv1 = pcurve->Value( f );
3140         edge.Reverse();
3141         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3142         if ( pcurve.IsNull() ) continue;
3143         uv2 = pcurve->Value( f );
3144         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3145         // assure uv1 < uv2
3146         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3147           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3148         }
3149         // get nodes on seam and its vertices
3150         list< const SMDS_MeshNode* > seamNodes;
3151         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3152         while ( nSeamIt->more() ) {
3153           const SMDS_MeshNode* node = nSeamIt->next();
3154           if ( !isQuadratic || !IsMedium( node ))
3155             seamNodes.push_back( node );
3156         }
3157         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3158         for ( ; vExp.More(); vExp.Next() ) {
3159           sm = aMesh->MeshElements( vExp.Current() );
3160           if ( sm ) {
3161             nSeamIt = sm->GetNodes();
3162             while ( nSeamIt->more() )
3163               seamNodes.push_back( nSeamIt->next() );
3164           }
3165         }
3166         // loop on nodes on seam
3167         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3168         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3169           const SMDS_MeshNode* nSeam = *noSeIt;
3170           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3171           if ( n_uv == uvMap.end() )
3172             continue;
3173           // set the first UV
3174           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3175           // set the second UV
3176           listUV.push_back( *n_uv->second );
3177           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3178           if ( uvMap2.empty() )
3179             uvMap2 = uvMap; // copy the uvMap contents
3180           uvMap2[ nSeam ] = &listUV.back();
3181
3182           // collect movable nodes linked to ones on seam in nodesNearSeam
3183           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3184           while ( eIt->more() ) {
3185             const SMDS_MeshElement* e = eIt->next();
3186             int nbUseMap1 = 0, nbUseMap2 = 0;
3187             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3188             int nn = 0, nbn =  e->NbNodes();
3189             if(e->IsQuadratic()) nbn = nbn/2;
3190             while ( nn++ < nbn )
3191             {
3192               const SMDS_MeshNode* n =
3193                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3194               if (n == nSeam ||
3195                   setMovableNodes.find( n ) == setMovableNodes.end() )
3196                 continue;
3197               // add only nodes being closer to uv2 than to uv1
3198               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3199                            0.5 * ( n->Y() + nSeam->Y() ),
3200                            0.5 * ( n->Z() + nSeam->Z() ));
3201               gp_XY uv;
3202               getClosestUV( projector, pMid, uv );
3203               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3204                 nodesNearSeam.insert( n );
3205                 nbUseMap2++;
3206               }
3207               else
3208                 nbUseMap1++;
3209             }
3210             // for centroidalSmooth all element nodes must
3211             // be on one side of a seam
3212             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3213               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3214               nn = 0;
3215               while ( nn++ < nbn ) {
3216                 const SMDS_MeshNode* n =
3217                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3218                 setMovableNodes.erase( n );
3219               }
3220             }
3221           }
3222         } // loop on nodes on seam
3223       } // loop on edge of a face
3224     } // if ( !face.IsNull() )
3225
3226     if ( setMovableNodes.empty() ) {
3227       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3228       continue; // goto next face
3229     }
3230
3231     // -------------
3232     // SMOOTHING //
3233     // -------------
3234
3235     int it = -1;
3236     double maxRatio = -1., maxDisplacement = -1.;
3237     set<const SMDS_MeshNode*>::iterator nodeToMove;
3238     for ( it = 0; it < theNbIterations; it++ ) {
3239       maxDisplacement = 0.;
3240       nodeToMove = setMovableNodes.begin();
3241       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3242         const SMDS_MeshNode* node = (*nodeToMove);
3243         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3244
3245         // smooth
3246         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3247         if ( theSmoothMethod == LAPLACIAN )
3248           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3249         else
3250           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3251
3252         // node displacement
3253         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3254         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3255         if ( aDispl > maxDisplacement )
3256           maxDisplacement = aDispl;
3257       }
3258       // no node movement => exit
3259       //if ( maxDisplacement < 1.e-16 ) {
3260       if ( maxDisplacement < disttol ) {
3261         MESSAGE("-- no node movement --");
3262         break;
3263       }
3264
3265       // check elements quality
3266       maxRatio  = 0;
3267       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3268       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3269         const SMDS_MeshElement* elem = (*elemIt);
3270         if ( !elem || elem->GetType() != SMDSAbs_Face )
3271           continue;
3272         SMESH::Controls::TSequenceOfXYZ aPoints;
3273         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3274           double aValue = aQualityFunc.GetValue( aPoints );
3275           if ( aValue > maxRatio )
3276             maxRatio = aValue;
3277         }
3278       }
3279       if ( maxRatio <= theTgtAspectRatio ) {
3280         MESSAGE("-- quality achived --");
3281         break;
3282       }
3283       if (it+1 == theNbIterations) {
3284         MESSAGE("-- Iteration limit exceeded --");
3285       }
3286     } // smoothing iterations
3287
3288     MESSAGE(" Face id: " << *fId <<
3289             " Nb iterstions: " << it <<
3290             " Displacement: " << maxDisplacement <<
3291             " Aspect Ratio " << maxRatio);
3292
3293     // ---------------------------------------
3294     // new nodes positions are computed,
3295     // record movement in DS and set new UV
3296     // ---------------------------------------
3297     nodeToMove = setMovableNodes.begin();
3298     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3299       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3300       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3301       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3302       if ( node_uv != uvMap.end() ) {
3303         gp_XY* uv = node_uv->second;
3304         node->SetPosition
3305           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3306       }
3307     }
3308
3309     // move medium nodes of quadratic elements
3310     if ( isQuadratic )
3311     {
3312       SMESH_MesherHelper helper( *GetMesh() );
3313       if ( !face.IsNull() )
3314         helper.SetSubShape( face );
3315       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3316       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3317         const SMDS_VtkFace* QF =
3318           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3319         if(QF && QF->IsQuadratic()) {
3320           vector<const SMDS_MeshNode*> Ns;
3321           Ns.reserve(QF->NbNodes()+1);
3322           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3323           while ( anIter->more() )
3324             Ns.push_back( cast2Node(anIter->next()) );
3325           Ns.push_back( Ns[0] );
3326           double x, y, z;
3327           for(int i=0; i<QF->NbNodes(); i=i+2) {
3328             if ( !surface.IsNull() ) {
3329               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3330               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3331               gp_XY uv = ( uv1 + uv2 ) / 2.;
3332               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3333               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3334             }
3335             else {
3336               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3337               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3338               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3339             }
3340             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3341                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3342                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3343               // we have to move i+1 node
3344               aMesh->MoveNode( Ns[i+1], x, y, z );
3345             }
3346           }
3347         }
3348       }
3349     }
3350
3351   } // loop on face ids
3352
3353 }
3354
3355 //=======================================================================
3356 //function : isReverse
3357 //purpose  : Return true if normal of prevNodes is not co-directied with
3358 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3359 //           iNotSame is where prevNodes and nextNodes are different
3360 //=======================================================================
3361
3362 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3363                       vector<const SMDS_MeshNode*> nextNodes,
3364                       const int            nbNodes,
3365                       const int            iNotSame)
3366 {
3367   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3368   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3369
3370   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3371   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3372   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3373   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3374
3375   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3376   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3377   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3378   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3379
3380   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3381
3382   return (vA ^ vB) * vN < 0.0;
3383 }
3384
3385 //=======================================================================
3386 /*!
3387  * \brief Create elements by sweeping an element
3388  * \param elem - element to sweep
3389  * \param newNodesItVec - nodes generated from each node of the element
3390  * \param newElems - generated elements
3391  * \param nbSteps - number of sweeping steps
3392  * \param srcElements - to append elem for each generated element
3393  */
3394 //=======================================================================
3395
3396 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3397                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3398                                     list<const SMDS_MeshElement*>&        newElems,
3399                                     const int                             nbSteps,
3400                                     SMESH_SequenceOfElemPtr&              srcElements)
3401 {
3402   //MESSAGE("sweepElement " << nbSteps);
3403   SMESHDS_Mesh* aMesh = GetMeshDS();
3404
3405   // Loop on elem nodes:
3406   // find new nodes and detect same nodes indices
3407   int nbNodes = elem->NbNodes();
3408   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3409   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3410   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3411   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3412
3413   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3414   vector<int> sames(nbNodes);
3415   vector<bool> issimple(nbNodes);
3416
3417   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3418     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3419     const SMDS_MeshNode*                 node         = nnIt->first;
3420     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3421     if ( listNewNodes.empty() ) {
3422       return;
3423     }
3424
3425     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3426
3427     itNN[ iNode ] = listNewNodes.begin();
3428     prevNod[ iNode ] = node;
3429     nextNod[ iNode ] = listNewNodes.front();
3430     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3431       if ( prevNod[ iNode ] != nextNod [ iNode ])
3432         iNotSameNode = iNode;
3433       else {
3434         iSameNode = iNode;
3435         //nbSame++;
3436         sames[nbSame++] = iNode;
3437       }
3438     }
3439   }
3440
3441   //cerr<<"  nbSame = "<<nbSame<<endl;
3442   if ( nbSame == nbNodes || nbSame > 2) {
3443     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3444     //INFOS( " Too many same nodes of element " << elem->GetID() );
3445     return;
3446   }
3447
3448   //  if( elem->IsQuadratic() && nbSame>0 ) {
3449   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3450   //    return;
3451   //  }
3452
3453   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3454   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3455   if ( nbSame > 0 ) {
3456     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3457     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3458     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3459   }
3460
3461   //if(nbNodes==8)
3462   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3463   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3464   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3465   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3466
3467   // check element orientation
3468   int i0 = 0, i2 = 2;
3469   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3470     //MESSAGE("Reversed elem " << elem );
3471     i0 = 2;
3472     i2 = 0;
3473     if ( nbSame > 0 )
3474       std::swap( iBeforeSame, iAfterSame );
3475   }
3476
3477   // make new elements
3478   const SMDS_MeshElement* lastElem = elem;
3479   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3480     // get next nodes
3481     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3482       if(issimple[iNode]) {
3483         nextNod[ iNode ] = *itNN[ iNode ];
3484         itNN[ iNode ]++;
3485       }
3486       else {
3487         if( elem->GetType()==SMDSAbs_Node ) {
3488           // we have to use two nodes
3489           midlNod[ iNode ] = *itNN[ iNode ];
3490           itNN[ iNode ]++;
3491           nextNod[ iNode ] = *itNN[ iNode ];
3492           itNN[ iNode ]++;
3493         }
3494         else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3495           // we have to use each second node
3496           //itNN[ iNode ]++;
3497           nextNod[ iNode ] = *itNN[ iNode ];
3498           itNN[ iNode ]++;
3499         }
3500         else {
3501           // we have to use two nodes
3502           midlNod[ iNode ] = *itNN[ iNode ];
3503           itNN[ iNode ]++;
3504           nextNod[ iNode ] = *itNN[ iNode ];
3505           itNN[ iNode ]++;
3506         }
3507       }
3508     }
3509     SMDS_MeshElement* aNewElem = 0;
3510     if(!elem->IsPoly()) {
3511       switch ( nbNodes ) {
3512       case 0:
3513         return;
3514       case 1: { // NODE
3515         if ( nbSame == 0 ) {
3516           if(issimple[0])
3517             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3518           else
3519             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3520         }
3521         break;
3522       }
3523       case 2: { // EDGE
3524         if ( nbSame == 0 )
3525           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3526                                     nextNod[ 1 ], nextNod[ 0 ] );
3527         else
3528           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3529                                     nextNod[ iNotSameNode ] );
3530         break;
3531       }
3532
3533       case 3: { // TRIANGLE or quadratic edge
3534         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3535
3536           if ( nbSame == 0 )       // --- pentahedron
3537             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3538                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3539
3540           else if ( nbSame == 1 )  // --- pyramid
3541             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3542                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3543                                          nextNod[ iSameNode ]);
3544
3545           else // 2 same nodes:      --- tetrahedron
3546             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3547                                          nextNod[ iNotSameNode ]);
3548         }
3549         else { // quadratic edge
3550           if(nbSame==0) {     // quadratic quadrangle
3551             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3552                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3553           }
3554           else if(nbSame==1) { // quadratic triangle
3555             if(sames[0]==2) {
3556               return; // medium node on axis
3557             }
3558             else if(sames[0]==0) {
3559               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3560                                         nextNod[2], midlNod[1], prevNod[2]);
3561             }
3562             else { // sames[0]==1
3563               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3564                                         midlNod[0], nextNod[2], prevNod[2]);
3565             }
3566           }
3567           else {
3568             return;
3569           }
3570         }
3571         break;
3572       }
3573       case 4: { // QUADRANGLE
3574
3575         if ( nbSame == 0 )       // --- hexahedron
3576           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3577                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3578
3579         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3580           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3581                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3582                                        nextNod[ iSameNode ]);
3583           newElems.push_back( aNewElem );
3584           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3585                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3586                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3587         }
3588         else if ( nbSame == 2 ) { // pentahedron
3589           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3590             // iBeforeSame is same too
3591             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3592                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3593                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3594           else
3595             // iAfterSame is same too
3596             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3597                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3598                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3599         }
3600         break;
3601       }
3602       case 6: { // quadratic triangle
3603         // create pentahedron with 15 nodes
3604         if(nbSame==0) {
3605           if(i0>0) { // reversed case
3606             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3607                                          nextNod[0], nextNod[2], nextNod[1],
3608                                          prevNod[5], prevNod[4], prevNod[3],
3609                                          nextNod[5], nextNod[4], nextNod[3],
3610                                          midlNod[0], midlNod[2], midlNod[1]);
3611           }
3612           else { // not reversed case
3613             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3614                                          nextNod[0], nextNod[1], nextNod[2],
3615                                          prevNod[3], prevNod[4], prevNod[5],
3616                                          nextNod[3], nextNod[4], nextNod[5],
3617                                          midlNod[0], midlNod[1], midlNod[2]);
3618           }
3619         }
3620         else if(nbSame==1) {
3621           // 2d order pyramid of 13 nodes
3622           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3623           //                                 int n12,int n23,int n34,int n41,
3624           //                                 int n15,int n25,int n35,int n45, int ID);
3625           int n5 = iSameNode;
3626           int n1,n4,n41,n15,n45;
3627           if(i0>0) { // reversed case
3628             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3629             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3630             n41 = n1 + 3;
3631             n15 = n5 + 3;
3632             n45 = n4 + 3;
3633           }
3634           else {
3635             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3636             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3637             n41 = n4 + 3;
3638             n15 = n1 + 3;
3639             n45 = n5 + 3;
3640           }
3641           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3642                                       nextNod[n4], prevNod[n4], prevNod[n5],
3643                                       midlNod[n1], nextNod[n41],
3644                                       midlNod[n4], prevNod[n41],
3645                                       prevNod[n15], nextNod[n15],
3646                                       nextNod[n45], prevNod[n45]);
3647         }
3648         else if(nbSame==2) {
3649           // 2d order tetrahedron of 10 nodes
3650           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3651           //                                 int n12,int n23,int n31,
3652           //                                 int n14,int n24,int n34, int ID);
3653           int n1 = iNotSameNode;
3654           int n2,n3,n12,n23,n31;
3655           if(i0>0) { // reversed case
3656             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3657             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3658             n12 = n2 + 3;
3659             n23 = n3 + 3;
3660             n31 = n1 + 3;
3661           }
3662           else {
3663             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3664             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3665             n12 = n1 + 3;
3666             n23 = n2 + 3;
3667             n31 = n3 + 3;
3668           }
3669           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3670                                        prevNod[n12], prevNod[n23], prevNod[n31],
3671                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3672         }
3673         break;
3674       }
3675       case 8: { // quadratic quadrangle
3676         if(nbSame==0) {
3677           // create hexahedron with 20 nodes
3678           if(i0>0) { // reversed case
3679             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3680                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3681                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3682                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3683                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3684           }
3685           else { // not reversed case
3686             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3687                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3688                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3689                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3690                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3691           }
3692         }
3693         else if(nbSame==1) { 
3694           // --- pyramid + pentahedron - can not be created since it is needed 
3695           // additional middle node ot the center of face
3696           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3697           return;
3698         }
3699         else if(nbSame==2) {
3700           // 2d order Pentahedron with 15 nodes
3701           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3702           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3703           //                                 int n14,int n25,int n36, int ID);
3704           int n1,n2,n4,n5;
3705           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3706             // iBeforeSame is same too
3707             n1 = iBeforeSame;
3708             n2 = iOpposSame;
3709             n4 = iSameNode;
3710             n5 = iAfterSame;
3711           }
3712           else {
3713             // iAfterSame is same too
3714             n1 = iSameNode;
3715             n2 = iBeforeSame;
3716             n4 = iAfterSame;
3717             n5 = iOpposSame;
3718           }
3719           int n12,n45,n14,n25;
3720           if(i0>0) { //reversed case
3721             n12 = n1 + 4;
3722             n45 = n5 + 4;
3723             n14 = n4 + 4;
3724             n25 = n2 + 4;
3725           }
3726           else {
3727             n12 = n2 + 4;
3728             n45 = n4 + 4;
3729             n14 = n1 + 4;
3730             n25 = n5 + 4;
3731           }
3732           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3733                                        prevNod[n4], prevNod[n5], nextNod[n5],
3734                                        prevNod[n12], midlNod[n2], nextNod[n12],
3735                                        prevNod[n45], midlNod[n5], nextNod[n45],
3736                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3737         }
3738         break;
3739       }
3740       default: {
3741         // realized for extrusion only
3742         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3743         //vector<int> quantities (nbNodes + 2);
3744
3745         //quantities[0] = nbNodes; // bottom of prism
3746         //for (int inode = 0; inode < nbNodes; inode++) {
3747         //  polyedre_nodes[inode] = prevNod[inode];
3748         //}
3749
3750         //quantities[1] = nbNodes; // top of prism
3751         //for (int inode = 0; inode < nbNodes; inode++) {
3752         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3753         //}
3754
3755         //for (int iface = 0; iface < nbNodes; iface++) {
3756         //  quantities[iface + 2] = 4;
3757         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3758         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3759         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3760         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3761         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3762         //}
3763         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3764         break;
3765       }
3766       }
3767     }
3768
3769     if(!aNewElem) {
3770       // realized for extrusion only
3771       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3772       vector<int> quantities (nbNodes + 2);
3773
3774       quantities[0] = nbNodes; // bottom of prism
3775       for (int inode = 0; inode < nbNodes; inode++) {
3776         polyedre_nodes[inode] = prevNod[inode];
3777       }
3778
3779       quantities[1] = nbNodes; // top of prism
3780       for (int inode = 0; inode < nbNodes; inode++) {
3781         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3782       }
3783
3784       for (int iface = 0; iface < nbNodes; iface++) {
3785         quantities[iface + 2] = 4;
3786         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3787         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3788         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3789         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3790         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3791       }
3792       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3793     }
3794
3795     if ( aNewElem ) {
3796       newElems.push_back( aNewElem );
3797       myLastCreatedElems.Append(aNewElem);
3798       srcElements.Append( elem );
3799       lastElem = aNewElem;
3800     }
3801
3802     // set new prev nodes
3803     for ( iNode = 0; iNode < nbNodes; iNode++ )
3804       prevNod[ iNode ] = nextNod[ iNode ];
3805
3806   } // for steps
3807 }
3808
3809 //=======================================================================
3810 /*!
3811  * \brief Create 1D and 2D elements around swept elements
3812  * \param mapNewNodes - source nodes and ones generated from them
3813  * \param newElemsMap - source elements and ones generated from them
3814  * \param elemNewNodesMap - nodes generated from each node of each element
3815  * \param elemSet - all swept elements
3816  * \param nbSteps - number of sweeping steps
3817  * \param srcElements - to append elem for each generated element
3818  */
3819 //=======================================================================
3820
3821 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3822                                   TElemOfElemListMap &     newElemsMap,
3823                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3824                                   TIDSortedElemSet&        elemSet,
3825                                   const int                nbSteps,
3826                                   SMESH_SequenceOfElemPtr& srcElements)
3827 {
3828   MESSAGE("makeWalls");
3829   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3830   SMESHDS_Mesh* aMesh = GetMeshDS();
3831
3832   // Find nodes belonging to only one initial element - sweep them to get edges.
3833
3834   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3835   for ( ; nList != mapNewNodes.end(); nList++ ) {
3836     const SMDS_MeshNode* node =
3837       static_cast<const SMDS_MeshNode*>( nList->first );
3838     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3839     int nbInitElems = 0;
3840     const SMDS_MeshElement* el = 0;
3841     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3842     while ( eIt->more() && nbInitElems < 2 ) {
3843       el = eIt->next();
3844       SMDSAbs_ElementType type = el->GetType();
3845       if ( type == SMDSAbs_Volume || type < highType ) continue;
3846       if ( type > highType ) {
3847         nbInitElems = 0;
3848         highType = type;
3849       }
3850       if ( elemSet.find(el) != elemSet.end() )
3851         nbInitElems++;
3852     }
3853     if ( nbInitElems < 2 ) {
3854       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3855       if(!NotCreateEdge) {
3856         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3857         list<const SMDS_MeshElement*> newEdges;
3858         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3859       }
3860     }
3861   }
3862
3863   // Make a ceiling for each element ie an equal element of last new nodes.
3864   // Find free links of faces - make edges and sweep them into faces.
3865
3866   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3867   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3868   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3869     const SMDS_MeshElement* elem = itElem->first;
3870     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3871
3872     if(itElem->second.size()==0) continue;
3873
3874     if ( elem->GetType() == SMDSAbs_Edge ) {
3875       // create a ceiling edge
3876       if (!elem->IsQuadratic()) {
3877         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3878                                vecNewNodes[ 1 ]->second.back())) {
3879           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3880                                                    vecNewNodes[ 1 ]->second.back()));
3881           srcElements.Append( myLastCreatedElems.Last() );
3882         }
3883       }
3884       else {
3885         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3886                                vecNewNodes[ 1 ]->second.back(),
3887                                vecNewNodes[ 2 ]->second.back())) {
3888           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3889                                                    vecNewNodes[ 1 ]->second.back(),
3890                                                    vecNewNodes[ 2 ]->second.back()));
3891           srcElements.Append( myLastCreatedElems.Last() );
3892         }
3893       }
3894     }
3895     if ( elem->GetType() != SMDSAbs_Face )
3896       continue;
3897
3898     bool hasFreeLinks = false;
3899
3900     TIDSortedElemSet avoidSet;
3901     avoidSet.insert( elem );
3902
3903     set<const SMDS_MeshNode*> aFaceLastNodes;
3904     int iNode, nbNodes = vecNewNodes.size();
3905     if(!elem->IsQuadratic()) {
3906       // loop on the face nodes
3907       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3908         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3909         // look for free links of the face
3910         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3911         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3912         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3913         // check if a link is free
3914         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3915           hasFreeLinks = true;
3916           // make an edge and a ceiling for a new edge
3917           if ( !aMesh->FindEdge( n1, n2 )) {
3918             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3919             srcElements.Append( myLastCreatedElems.Last() );
3920           }
3921           n1 = vecNewNodes[ iNode ]->second.back();
3922           n2 = vecNewNodes[ iNext ]->second.back();
3923           if ( !aMesh->FindEdge( n1, n2 )) {
3924             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3925             srcElements.Append( myLastCreatedElems.Last() );
3926           }
3927         }
3928       }
3929     }
3930     else { // elem is quadratic face
3931       int nbn = nbNodes/2;
3932       for ( iNode = 0; iNode < nbn; iNode++ ) {
3933         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3934         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3935         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3936         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3937         // check if a link is free
3938         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3939           hasFreeLinks = true;
3940           // make an edge and a ceiling for a new edge
3941           // find medium node
3942           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3943           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3944             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3945             srcElements.Append( myLastCreatedElems.Last() );
3946           }
3947           n1 = vecNewNodes[ iNode ]->second.back();
3948           n2 = vecNewNodes[ iNext ]->second.back();
3949           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3950           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3951             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3952             srcElements.Append( myLastCreatedElems.Last() );
3953           }
3954         }
3955       }
3956       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3957         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3958       }
3959     }
3960
3961     // sweep free links into faces
3962
3963     if ( hasFreeLinks )  {
3964       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3965       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3966
3967       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3968       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3969         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3970         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3971       }
3972       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3973         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3974         iVol = 0;
3975         while ( iVol++ < volNb ) v++;
3976         // find indices of free faces of a volume and their source edges
3977         list< int > freeInd;
3978         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3979         SMDS_VolumeTool vTool( *v );
3980         int iF, nbF = vTool.NbFaces();
3981         for ( iF = 0; iF < nbF; iF ++ ) {
3982           if (vTool.IsFreeFace( iF ) &&
3983               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3984               initNodeSet != faceNodeSet) // except an initial face
3985           {
3986             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3987               continue;
3988             freeInd.push_back( iF );
3989             // find source edge of a free face iF
3990             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3991             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3992             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3993                                    initNodeSet.begin(), initNodeSet.end(),
3994                                    commonNodes.begin());
3995             if ( (*v)->IsQuadratic() )
3996               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3997             else
3998               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3999 #ifdef _DEBUG_
4000             if ( !srcEdges.back() )
4001             {
4002               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4003                    << iF << " of volume #" << vTool.ID() << endl;
4004             }
4005 #endif
4006           }
4007         }
4008         if ( freeInd.empty() )
4009           continue;
4010
4011         // create faces for all steps;
4012         // if such a face has been already created by sweep of edge,
4013         // assure that its orientation is OK
4014         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
4015           vTool.Set( *v );
4016           vTool.SetExternalNormal();
4017           const int nextShift = vTool.IsForward() ? +1 : -1;
4018           list< int >::iterator ind = freeInd.begin();
4019           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4020           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4021           {
4022             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4023             int nbn = vTool.NbFaceNodes( *ind );
4024             if ( ! (*v)->IsPoly() )
4025               switch ( nbn ) {
4026               case 3: { ///// triangle
4027                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4028                 if ( !f ||
4029                      nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4030                 {
4031                   const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4032                                                        nodes[ 1 ],
4033                                                        nodes[ 1 + nextShift ] };
4034                   if ( f )
4035                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4036                   else
4037                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4038                                                               newOrder[ 2 ] ));
4039                 }
4040                 break;
4041               }
4042               case 4: { ///// quadrangle
4043                 const SMDS_MeshFace * f =
4044                   aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4045                 if ( !f ||
4046                      nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4047                 {
4048                   const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4049                                                        nodes[ 2 ], nodes[ 2+nextShift ] };
4050                   if ( f )
4051                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4052                   else
4053                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4054                                                               newOrder[ 2 ], newOrder[ 3 ]));
4055                 }
4056                 break;
4057               }
4058               case 6: { /////// quadratic triangle
4059                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4060                                                            nodes[1], nodes[3], nodes[5] );
4061                 if ( !f ||
4062                      nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4063                 {
4064                   const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4065                                                        nodes[2],
4066                                                        nodes[2 + 2*nextShift],
4067                                                        nodes[3 - 2*nextShift],
4068                                                        nodes[3],
4069                                                        nodes[3 + 2*nextShift]};
4070                   if ( f )
4071                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4072                   else
4073                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4074                                                               newOrder[ 1 ],
4075                                                               newOrder[ 2 ],
4076                                                               newOrder[ 3 ],
4077                                                               newOrder[ 4 ],
4078                                                               newOrder[ 5 ] ));
4079                 }
4080                 break;
4081               }
4082               default:       /////// quadratic quadrangle
4083                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4084                                                            nodes[1], nodes[3], nodes[5], nodes[7] );
4085                 if ( !f ||
4086                      nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4087                 {
4088                   const SMDS_MeshNode* newOrder[8] = { nodes[0],
4089                                                        nodes[4 - 2*nextShift],
4090                                                        nodes[4],
4091                                                        nodes[4 + 2*nextShift],
4092                                                        nodes[1],
4093                                                        nodes[5 - 2*nextShift],
4094                                                        nodes[5],
4095                                                        nodes[5 + 2*nextShift] };
4096                   if ( f )
4097                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4098                   else
4099                     myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4100                                                              newOrder[ 2 ], newOrder[ 3 ],
4101                                                              newOrder[ 4 ], newOrder[ 5 ],
4102                                                              newOrder[ 6 ], newOrder[ 7 ]));
4103                 }
4104               } // switch ( nbn )
4105
4106             else { //////// polygon
4107
4108               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4109               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4110               if ( !f ||
4111                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4112               {
4113                 if ( !vTool.IsForward() )
4114                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4115                 if ( f )
4116                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4117                 else
4118                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4119               }
4120             }
4121
4122             while ( srcElements.Length() < myLastCreatedElems.Length() )
4123               srcElements.Append( *srcEdge );
4124
4125           }  // loop on free faces
4126
4127           // go to the next volume
4128           iVol = 0;
4129           while ( iVol++ < nbVolumesByStep ) v++;
4130
4131         } // loop on steps
4132       } // loop on volumes of one step
4133     } // sweep free links into faces
4134
4135     // Make a ceiling face with a normal external to a volume
4136
4137     SMDS_VolumeTool lastVol( itElem->second.back() );
4138
4139     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4140     if ( iF >= 0 ) {
4141       lastVol.SetExternalNormal();
4142       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4143       int nbn = lastVol.NbFaceNodes( iF );
4144       switch ( nbn ) {
4145       case 3:
4146         if (!hasFreeLinks ||
4147             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4148           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4149         break;
4150       case 4:
4151         if (!hasFreeLinks ||
4152             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4153           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4154         break;
4155       default:
4156         if(itElem->second.back()->IsQuadratic()) {
4157           if(nbn==6) {
4158             if (!hasFreeLinks ||
4159                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4160                                  nodes[1], nodes[3], nodes[5]) ) {
4161               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4162                                                        nodes[1], nodes[3], nodes[5]));
4163             }
4164           }
4165           else { // nbn==8
4166             if (!hasFreeLinks ||
4167                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4168                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4169               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4170                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4171           }
4172         }
4173         else {
4174           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4175           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4176             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4177         }
4178       } // switch
4179
4180       while ( srcElements.Length() < myLastCreatedElems.Length() )
4181         srcElements.Append( myLastCreatedElems.Last() );
4182     }
4183   } // loop on swept elements
4184 }
4185
4186 //=======================================================================
4187 //function : RotationSweep
4188 //purpose  :
4189 //=======================================================================
4190
4191 SMESH_MeshEditor::PGroupIDs
4192 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4193                                 const gp_Ax1&      theAxis,
4194                                 const double       theAngle,
4195                                 const int          theNbSteps,
4196                                 const double       theTol,
4197                                 const bool         theMakeGroups,
4198                                 const bool         theMakeWalls)
4199 {
4200   myLastCreatedElems.Clear();
4201   myLastCreatedNodes.Clear();
4202
4203   // source elements for each generated one
4204   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4205
4206   MESSAGE( "RotationSweep()");
4207   gp_Trsf aTrsf;
4208   aTrsf.SetRotation( theAxis, theAngle );
4209   gp_Trsf aTrsf2;
4210   aTrsf2.SetRotation( theAxis, theAngle/2. );
4211
4212   gp_Lin aLine( theAxis );
4213   double aSqTol = theTol * theTol;
4214
4215   SMESHDS_Mesh* aMesh = GetMeshDS();
4216
4217   TNodeOfNodeListMap mapNewNodes;
4218   TElemOfVecOfNnlmiMap mapElemNewNodes;
4219   TElemOfElemListMap newElemsMap;
4220
4221   // loop on theElems
4222   TIDSortedElemSet::iterator itElem;
4223   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4224     const SMDS_MeshElement* elem = *itElem;
4225     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4226       continue;
4227     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4228     newNodesItVec.reserve( elem->NbNodes() );
4229
4230     // loop on elem nodes
4231     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4232     while ( itN->more() ) {
4233       // check if a node has been already sweeped
4234       const SMDS_MeshNode* node = cast2Node( itN->next() );
4235
4236       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4237       double coord[3];
4238       aXYZ.Coord( coord[0], coord[1], coord[2] );
4239       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4240
4241       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4242       if ( nIt == mapNewNodes.end() ) {
4243         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4244         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4245
4246         // make new nodes
4247         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4248         //double coord[3];
4249         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4250         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4251         const SMDS_MeshNode * newNode = node;
4252         for ( int i = 0; i < theNbSteps; i++ ) {
4253           if ( !isOnAxis ) {
4254             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4255               // create two nodes
4256               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4257               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4258               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4259               myLastCreatedNodes.Append(newNode);
4260               srcNodes.Append( node );
4261               listNewNodes.push_back( newNode );
4262               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4263               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4264             }
4265             else {
4266               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4267             }
4268             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4269             myLastCreatedNodes.Append(newNode);
4270             srcNodes.Append( node );
4271             listNewNodes.push_back( newNode );
4272           }
4273           else {
4274             listNewNodes.push_back( newNode );
4275             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4276               listNewNodes.push_back( newNode );
4277             }
4278           }
4279         }
4280       }
4281       /*
4282         else {
4283         // if current elem is quadratic and current node is not medium
4284         // we have to check - may be it is needed to insert additional nodes
4285         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4286         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4287         if(listNewNodes.size()==theNbSteps) {
4288         listNewNodes.clear();
4289         // make new nodes
4290         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4291         //double coord[3];
4292         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4293         const SMDS_MeshNode * newNode = node;
4294         if ( !isOnAxis ) {
4295         for(int i = 0; i<theNbSteps; i++) {
4296         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4297         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4298         cout<<"    3 AddNode:  "<<newNode;
4299         myLastCreatedNodes.Append(newNode);
4300         listNewNodes.push_back( newNode );
4301         srcNodes.Append( node );
4302         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4303         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4304         cout<<"    4 AddNode:  "<<newNode;
4305         myLastCreatedNodes.Append(newNode);
4306         srcNodes.Append( node );
4307         listNewNodes.push_back( newNode );
4308         }
4309         }
4310         else {
4311         listNewNodes.push_back( newNode );
4312         }
4313         }
4314         }
4315         }
4316       */
4317       newNodesItVec.push_back( nIt );
4318     }
4319     // make new elements
4320     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4321   }
4322
4323   if ( theMakeWalls )
4324     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4325
4326   PGroupIDs newGroupIDs;
4327   if ( theMakeGroups )
4328     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4329
4330   return newGroupIDs;
4331 }
4332
4333
4334 //=======================================================================
4335 //function : CreateNode
4336 //purpose  :
4337 //=======================================================================
4338 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4339                                                   const double y,
4340                                                   const double z,
4341                                                   const double tolnode,
4342                                                   SMESH_SequenceOfNode& aNodes)
4343 {
4344   myLastCreatedElems.Clear();
4345   myLastCreatedNodes.Clear();
4346
4347   gp_Pnt P1(x,y,z);
4348   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4349
4350   // try to search in sequence of existing nodes
4351   // if aNodes.Length()>0 we 'nave to use given sequence
4352   // else - use all nodes of mesh
4353   if(aNodes.Length()>0) {
4354     int i;
4355     for(i=1; i<=aNodes.Length(); i++) {
4356       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4357       if(P1.Distance(P2)<tolnode)
4358         return aNodes.Value(i);
4359     }
4360   }
4361   else {
4362     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4363     while(itn->more()) {
4364       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4365       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4366       if(P1.Distance(P2)<tolnode)
4367         return aN;
4368     }
4369   }
4370
4371   // create new node and return it
4372   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4373   myLastCreatedNodes.Append(NewNode);
4374   return NewNode;
4375 }
4376
4377
4378 //=======================================================================
4379 //function : ExtrusionSweep
4380 //purpose  :
4381 //=======================================================================
4382
4383 SMESH_MeshEditor::PGroupIDs
4384 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4385                                   const gp_Vec&       theStep,
4386                                   const int           theNbSteps,
4387                                   TElemOfElemListMap& newElemsMap,
4388                                   const bool          theMakeGroups,
4389                                   const int           theFlags,
4390                                   const double        theTolerance)
4391 {
4392   ExtrusParam aParams;
4393   aParams.myDir = gp_Dir(theStep);
4394   aParams.myNodes.Clear();
4395   aParams.mySteps = new TColStd_HSequenceOfReal;
4396   int i;
4397   for(i=1; i<=theNbSteps; i++)
4398     aParams.mySteps->Append(theStep.Magnitude());
4399
4400   return
4401     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4402 }
4403
4404
4405 //=======================================================================
4406 //function : ExtrusionSweep
4407 //purpose  :
4408 //=======================================================================
4409
4410 SMESH_MeshEditor::PGroupIDs
4411 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4412                                   ExtrusParam&        theParams,
4413                                   TElemOfElemListMap& newElemsMap,
4414                                   const bool          theMakeGroups,
4415                                   const int           theFlags,
4416                                   const double        theTolerance)
4417 {
4418   MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4419   myLastCreatedElems.Clear();
4420   myLastCreatedNodes.Clear();
4421
4422   // source elements for each generated one
4423   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4424
4425   SMESHDS_Mesh* aMesh = GetMeshDS();
4426
4427   int nbsteps = theParams.mySteps->Length();
4428
4429   TNodeOfNodeListMap mapNewNodes;
4430   //TNodeOfNodeVecMap mapNewNodes;
4431   TElemOfVecOfNnlmiMap mapElemNewNodes;
4432   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4433
4434   // loop on theElems
4435   TIDSortedElemSet::iterator itElem;
4436   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4437     // check element type
4438     const SMDS_MeshElement* elem = *itElem;
4439     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4440       continue;
4441
4442     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4443     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4444     newNodesItVec.reserve( elem->NbNodes() );
4445
4446     // loop on elem nodes
4447     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4448     while ( itN->more() )
4449     {
4450       // check if a node has been already sweeped
4451       const SMDS_MeshNode* node = cast2Node( itN->next() );
4452       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4453       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4454       if ( nIt == mapNewNodes.end() ) {
4455         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4456         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4457         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4458         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4459         //vecNewNodes.reserve(nbsteps);
4460
4461         // make new nodes
4462         double coord[] = { node->X(), node->Y(), node->Z() };
4463         //int nbsteps = theParams.mySteps->Length();
4464         for ( int i = 0; i < nbsteps; i++ ) {
4465           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4466             // create additional node
4467             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4468             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4469             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4470             if( theFlags & EXTRUSION_FLAG_SEW ) {
4471               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4472                                                          theTolerance, theParams.myNodes);
4473               listNewNodes.push_back( newNode );
4474             }
4475             else {
4476               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4477               myLastCreatedNodes.Append(newNode);
4478               srcNodes.Append( node );
4479               listNewNodes.push_back( newNode );
4480             }
4481           }
4482           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4483           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4484           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4485           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4486           if( theFlags & EXTRUSION_FLAG_SEW ) {
4487             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4488                                                        theTolerance, theParams.myNodes);
4489             listNewNodes.push_back( newNode );
4490             //vecNewNodes[i]=newNode;
4491           }
4492           else {
4493             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4494             myLastCreatedNodes.Append(newNode);
4495             srcNodes.Append( node );
4496             listNewNodes.push_back( newNode );
4497             //vecNewNodes[i]=newNode;
4498           }
4499         }
4500       }
4501       else {
4502         // if current elem is quadratic and current node is not medium
4503         // we have to check - may be it is needed to insert additional nodes
4504         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4505           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4506           if(listNewNodes.size()==nbsteps) {
4507             listNewNodes.clear();
4508             double coord[] = { node->X(), node->Y(), node->Z() };
4509             for ( int i = 0; i < nbsteps; i++ ) {
4510               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4511               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4512               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4513               if( theFlags & EXTRUSION_FLAG_SEW ) {
4514                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4515                                                            theTolerance, theParams.myNodes);
4516                 listNewNodes.push_back( newNode );
4517               }
4518               else {
4519                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4520                 myLastCreatedNodes.Append(newNode);
4521                 srcNodes.Append( node );
4522                 listNewNodes.push_back( newNode );
4523               }
4524               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4525               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4526               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4527               if( theFlags & EXTRUSION_FLAG_SEW ) {
4528                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4529                                                            theTolerance, theParams.myNodes);
4530                 listNewNodes.push_back( newNode );
4531               }
4532               else {
4533                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4534                 myLastCreatedNodes.Append(newNode);
4535                 srcNodes.Append( node );
4536                 listNewNodes.push_back( newNode );
4537               }
4538             }
4539           }
4540         }
4541       }
4542       newNodesItVec.push_back( nIt );
4543     }
4544     // make new elements
4545     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4546   }
4547
4548   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4549     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4550   }
4551   PGroupIDs newGroupIDs;
4552   if ( theMakeGroups )
4553     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4554
4555   return newGroupIDs;
4556 }
4557
4558 /*
4559 //=======================================================================
4560 //class    : SMESH_MeshEditor_PathPoint
4561 //purpose  : auxiliary class
4562 //=======================================================================
4563 class SMESH_MeshEditor_PathPoint {
4564 public:
4565 SMESH_MeshEditor_PathPoint() {
4566 myPnt.SetCoord(99., 99., 99.);
4567 myTgt.SetCoord(1.,0.,0.);
4568 myAngle=0.;
4569 myPrm=0.;
4570 }
4571 void SetPnt(const gp_Pnt& aP3D){
4572 myPnt=aP3D;
4573 }
4574 void SetTangent(const gp_Dir& aTgt){
4575 myTgt=aTgt;
4576 }
4577 void SetAngle(const double& aBeta){
4578 myAngle=aBeta;
4579 }
4580 void SetParameter(const double& aPrm){
4581 myPrm=aPrm;
4582 }
4583 const gp_Pnt& Pnt()const{
4584 return myPnt;
4585 }
4586 const gp_Dir& Tangent()const{
4587 return myTgt;
4588 }
4589 double Angle()const{
4590 return myAngle;
4591 }
4592 double Parameter()const{
4593 return myPrm;
4594 }
4595
4596 protected:
4597 gp_Pnt myPnt;
4598 gp_Dir myTgt;
4599 double myAngle;
4600 double myPrm;
4601 };
4602 */
4603
4604 //=======================================================================
4605 //function : ExtrusionAlongTrack
4606 //purpose  :
4607 //=======================================================================
4608 SMESH_MeshEditor::Extrusion_Error
4609 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4610                                        SMESH_subMesh*       theTrack,
4611                                        const SMDS_MeshNode* theN1,
4612                                        const bool           theHasAngles,
4613                                        list<double>&        theAngles,
4614                                        const bool           theLinearVariation,
4615                                        const bool           theHasRefPoint,
4616                                        const gp_Pnt&        theRefPoint,
4617                                        const bool           theMakeGroups)
4618 {
4619   MESSAGE("ExtrusionAlongTrack");
4620   myLastCreatedElems.Clear();
4621   myLastCreatedNodes.Clear();
4622
4623   int aNbE;
4624   std::list<double> aPrms;
4625   TIDSortedElemSet::iterator itElem;
4626
4627   gp_XYZ aGC;
4628   TopoDS_Edge aTrackEdge;
4629   TopoDS_Vertex aV1, aV2;
4630
4631   SMDS_ElemIteratorPtr aItE;
4632   SMDS_NodeIteratorPtr aItN;
4633   SMDSAbs_ElementType aTypeE;
4634
4635   TNodeOfNodeListMap mapNewNodes;
4636
4637   // 1. Check data
4638   aNbE = theElements.size();
4639   // nothing to do
4640   if ( !aNbE )
4641     return EXTR_NO_ELEMENTS;
4642
4643   // 1.1 Track Pattern
4644   ASSERT( theTrack );
4645
4646   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4647
4648   aItE = pSubMeshDS->GetElements();
4649   while ( aItE->more() ) {
4650     const SMDS_MeshElement* pE = aItE->next();
4651     aTypeE = pE->GetType();
4652     // Pattern must contain links only
4653     if ( aTypeE != SMDSAbs_Edge )
4654       return EXTR_PATH_NOT_EDGE;
4655   }
4656
4657   list<SMESH_MeshEditor_PathPoint> fullList;
4658
4659   const TopoDS_Shape& aS = theTrack->GetSubShape();
4660   // Sub shape for the Pattern must be an Edge or Wire
4661   if( aS.ShapeType() == TopAbs_EDGE ) {
4662     aTrackEdge = TopoDS::Edge( aS );
4663     // the Edge must not be degenerated
4664     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4665       return EXTR_BAD_PATH_SHAPE;
4666     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4667     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4668     const SMDS_MeshNode* aN1 = aItN->next();
4669     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4670     const SMDS_MeshNode* aN2 = aItN->next();
4671     // starting node must be aN1 or aN2
4672     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4673       return EXTR_BAD_STARTING_NODE;
4674     aItN = pSubMeshDS->GetNodes();
4675     while ( aItN->more() ) {
4676       const SMDS_MeshNode* pNode = aItN->next();
4677       const SMDS_EdgePosition* pEPos =
4678         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4679       double aT = pEPos->GetUParameter();
4680       aPrms.push_back( aT );
4681     }
4682     //Extrusion_Error err =
4683     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4684   }
4685   else if( aS.ShapeType() == TopAbs_WIRE ) {
4686     list< SMESH_subMesh* > LSM;
4687     TopTools_SequenceOfShape Edges;
4688     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4689     while(itSM->more()) {
4690       SMESH_subMesh* SM = itSM->next();
4691       LSM.push_back(SM);
4692       const TopoDS_Shape& aS = SM->GetSubShape();
4693       Edges.Append(aS);
4694     }
4695     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4696     int startNid = theN1->GetID();
4697     TColStd_MapOfInteger UsedNums;
4698     int NbEdges = Edges.Length();
4699     int i = 1;
4700     for(; i<=NbEdges; i++) {
4701       int k = 0;
4702       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4703       for(; itLSM!=LSM.end(); itLSM++) {
4704         k++;
4705         if(UsedNums.Contains(k)) continue;
4706         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4707         SMESH_subMesh* locTrack = *itLSM;
4708         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4709         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4710         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4711         const SMDS_MeshNode* aN1 = aItN->next();
4712         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4713         const SMDS_MeshNode* aN2 = aItN->next();
4714         // starting node must be aN1 or aN2
4715         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4716         // 2. Collect parameters on the track edge
4717         aPrms.clear();
4718         aItN = locMeshDS->GetNodes();
4719         while ( aItN->more() ) {
4720           const SMDS_MeshNode* pNode = aItN->next();
4721           const SMDS_EdgePosition* pEPos =
4722             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4723           double aT = pEPos->GetUParameter();
4724           aPrms.push_back( aT );
4725         }
4726         list<SMESH_MeshEditor_PathPoint> LPP;
4727         //Extrusion_Error err =
4728         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4729         LLPPs.push_back(LPP);
4730         UsedNums.Add(k);
4731         // update startN for search following egde
4732         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4733         else startNid = aN1->GetID();
4734         break;
4735       }
4736     }
4737     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4738     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4739     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4740     for(; itPP!=firstList.end(); itPP++) {
4741       fullList.push_back( *itPP );
4742     }
4743     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4744     fullList.pop_back();
4745     itLLPP++;
4746     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4747       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4748       itPP = currList.begin();
4749       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4750       gp_Dir D1 = PP1.Tangent();
4751       gp_Dir D2 = PP2.Tangent();
4752       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4753                            (D1.Z()+D2.Z())/2 ) );
4754       PP1.SetTangent(Dnew);
4755       fullList.push_back(PP1);
4756       itPP++;
4757       for(; itPP!=firstList.end(); itPP++) {
4758         fullList.push_back( *itPP );
4759       }
4760       PP1 = fullList.back();
4761       fullList.pop_back();
4762     }
4763     // if wire not closed
4764     fullList.push_back(PP1);
4765     // else ???
4766   }
4767   else {
4768     return EXTR_BAD_PATH_SHAPE;
4769   }
4770
4771   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4772                           theHasRefPoint, theRefPoint, theMakeGroups);
4773 }
4774
4775
4776 //=======================================================================
4777 //function : ExtrusionAlongTrack
4778 //purpose  :
4779 //=======================================================================
4780 SMESH_MeshEditor::Extrusion_Error
4781 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4782                                        SMESH_Mesh*          theTrack,
4783                                        const SMDS_MeshNode* theN1,
4784                                        const bool           theHasAngles,
4785                                        list<double>&        theAngles,
4786                                        const bool           theLinearVariation,
4787                                        const bool           theHasRefPoint,
4788                                        const gp_Pnt&        theRefPoint,
4789                                        const bool           theMakeGroups)
4790 {
4791   myLastCreatedElems.Clear();
4792   myLastCreatedNodes.Clear();
4793
4794   int aNbE;
4795   std::list<double> aPrms;
4796   TIDSortedElemSet::iterator itElem;
4797
4798   gp_XYZ aGC;
4799   TopoDS_Edge aTrackEdge;
4800   TopoDS_Vertex aV1, aV2;
4801
4802   SMDS_ElemIteratorPtr aItE;
4803   SMDS_NodeIteratorPtr aItN;
4804   SMDSAbs_ElementType aTypeE;
4805
4806   TNodeOfNodeListMap mapNewNodes;
4807
4808   // 1. Check data
4809   aNbE = theElements.size();
4810   // nothing to do
4811   if ( !aNbE )
4812     return EXTR_NO_ELEMENTS;
4813
4814   // 1.1 Track Pattern
4815   ASSERT( theTrack );
4816
4817   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4818
4819   aItE = pMeshDS->elementsIterator();
4820   while ( aItE->more() ) {
4821     const SMDS_MeshElement* pE = aItE->next();
4822     aTypeE = pE->GetType();
4823     // Pattern must contain links only
4824     if ( aTypeE != SMDSAbs_Edge )
4825       return EXTR_PATH_NOT_EDGE;
4826   }
4827
4828   list<SMESH_MeshEditor_PathPoint> fullList;
4829
4830   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4831   // Sub shape for the Pattern must be an Edge or Wire
4832   if( aS.ShapeType() == TopAbs_EDGE ) {
4833     aTrackEdge = TopoDS::Edge( aS );
4834     // the Edge must not be degenerated
4835     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4836       return EXTR_BAD_PATH_SHAPE;
4837     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4838     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4839     const SMDS_MeshNode* aN1 = aItN->next();
4840     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4841     const SMDS_MeshNode* aN2 = aItN->next();
4842     // starting node must be aN1 or aN2
4843     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4844       return EXTR_BAD_STARTING_NODE;
4845     aItN = pMeshDS->nodesIterator();
4846     while ( aItN->more() ) {
4847       const SMDS_MeshNode* pNode = aItN->next();
4848       if( pNode==aN1 || pNode==aN2 ) continue;
4849       const SMDS_EdgePosition* pEPos =
4850         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4851       double aT = pEPos->GetUParameter();
4852       aPrms.push_back( aT );
4853     }
4854     //Extrusion_Error err =
4855     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4856   }
4857   else if( aS.ShapeType() == TopAbs_WIRE ) {
4858     list< SMESH_subMesh* > LSM;
4859     TopTools_SequenceOfShape Edges;
4860     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4861     for(; eExp.More(); eExp.Next()) {
4862       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4863       if( BRep_Tool::Degenerated(E) ) continue;
4864       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4865       if(SM) {
4866         LSM.push_back(SM);
4867         Edges.Append(E);
4868       }
4869     }
4870     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4871     int startNid = theN1->GetID();
4872     TColStd_MapOfInteger UsedNums;
4873     int NbEdges = Edges.Length();
4874     int i = 1;
4875     for(; i<=NbEdges; i++) {
4876       int k = 0;
4877       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4878       for(; itLSM!=LSM.end(); itLSM++) {
4879         k++;
4880         if(UsedNums.Contains(k)) continue;
4881         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4882         SMESH_subMesh* locTrack = *itLSM;
4883         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4884         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4885         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4886         const SMDS_MeshNode* aN1 = aItN->next();
4887         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4888         const SMDS_MeshNode* aN2 = aItN->next();
4889         // starting node must be aN1 or aN2
4890         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4891         // 2. Collect parameters on the track edge
4892         aPrms.clear();
4893         aItN = locMeshDS->GetNodes();
4894         while ( aItN->more() ) {
4895           const SMDS_MeshNode* pNode = aItN->next();
4896           const SMDS_EdgePosition* pEPos =
4897             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4898           double aT = pEPos->GetUParameter();
4899           aPrms.push_back( aT );
4900         }
4901         list<SMESH_MeshEditor_PathPoint> LPP;
4902         //Extrusion_Error err =
4903         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4904         LLPPs.push_back(LPP);
4905         UsedNums.Add(k);
4906         // update startN for search following egde
4907         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4908         else startNid = aN1->GetID();
4909         break;
4910       }
4911     }
4912     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4913     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4914     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4915     for(; itPP!=firstList.end(); itPP++) {
4916       fullList.push_back( *itPP );
4917     }
4918     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4919     fullList.pop_back();
4920     itLLPP++;
4921     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4922       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4923       itPP = currList.begin();
4924       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4925       gp_Dir D1 = PP1.Tangent();
4926       gp_Dir D2 = PP2.Tangent();
4927       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4928                            (D1.Z()+D2.Z())/2 ) );
4929       PP1.SetTangent(Dnew);
4930       fullList.push_back(PP1);
4931       itPP++;
4932       for(; itPP!=currList.end(); itPP++) {
4933         fullList.push_back( *itPP );
4934       }
4935       PP1 = fullList.back();
4936       fullList.pop_back();
4937     }
4938     // if wire not closed
4939     fullList.push_back(PP1);
4940     // else ???
4941   }
4942   else {
4943     return EXTR_BAD_PATH_SHAPE;
4944   }
4945
4946   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4947                           theHasRefPoint, theRefPoint, theMakeGroups);
4948 }
4949
4950
4951 //=======================================================================
4952 //function : MakeEdgePathPoints
4953 //purpose  : auxilary for ExtrusionAlongTrack
4954 //=======================================================================
4955 SMESH_MeshEditor::Extrusion_Error
4956 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4957                                      const TopoDS_Edge& aTrackEdge,
4958                                      bool FirstIsStart,
4959                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4960 {
4961   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4962   aTolVec=1.e-7;
4963   aTolVec2=aTolVec*aTolVec;
4964   double aT1, aT2;
4965   TopoDS_Vertex aV1, aV2;
4966   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4967   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4968   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4969   // 2. Collect parameters on the track edge
4970   aPrms.push_front( aT1 );
4971   aPrms.push_back( aT2 );
4972   // sort parameters
4973   aPrms.sort();
4974   if( FirstIsStart ) {
4975     if ( aT1 > aT2 ) {
4976       aPrms.reverse();
4977     }
4978   }
4979   else {
4980     if ( aT2 > aT1 ) {
4981       aPrms.reverse();
4982     }
4983   }
4984   // 3. Path Points
4985   SMESH_MeshEditor_PathPoint aPP;
4986   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4987   std::list<double>::iterator aItD = aPrms.begin();
4988   for(; aItD != aPrms.end(); ++aItD) {
4989     double aT = *aItD;
4990     gp_Pnt aP3D;
4991     gp_Vec aVec;
4992     aC3D->D1( aT, aP3D, aVec );
4993     aL2 = aVec.SquareMagnitude();
4994     if ( aL2 < aTolVec2 )
4995       return EXTR_CANT_GET_TANGENT;
4996     gp_Dir aTgt( aVec );
4997     aPP.SetPnt( aP3D );
4998     aPP.SetTangent( aTgt );
4999     aPP.SetParameter( aT );
5000     LPP.push_back(aPP);
5001   }
5002   return EXTR_OK;
5003 }
5004
5005
5006 //=======================================================================
5007 //function : MakeExtrElements
5008 //purpose  : auxilary for ExtrusionAlongTrack
5009 //=======================================================================
5010 SMESH_MeshEditor::Extrusion_Error
5011 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5012                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5013                                    const bool theHasAngles,
5014                                    list<double>& theAngles,
5015                                    const bool theLinearVariation,
5016                                    const bool theHasRefPoint,
5017                                    const gp_Pnt& theRefPoint,
5018                                    const bool theMakeGroups)
5019 {
5020   MESSAGE("MakeExtrElements");
5021   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5022   int aNbTP = fullList.size();
5023   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5024   // Angles
5025   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5026     LinearAngleVariation(aNbTP-1, theAngles);
5027   }
5028   vector<double> aAngles( aNbTP );
5029   int j = 0;
5030   for(; j<aNbTP; ++j) {
5031     aAngles[j] = 0.;
5032   }
5033   if ( theHasAngles ) {
5034     double anAngle;;
5035     std::list<double>::iterator aItD = theAngles.begin();
5036     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5037       anAngle = *aItD;
5038       aAngles[j] = anAngle;
5039     }
5040   }
5041   // fill vector of path points with angles
5042   //aPPs.resize(fullList.size());
5043   j = -1;
5044   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5045   for(; itPP!=fullList.end(); itPP++) {
5046     j++;
5047     SMESH_MeshEditor_PathPoint PP = *itPP;
5048     PP.SetAngle(aAngles[j]);
5049     aPPs[j] = PP;
5050   }
5051
5052   TNodeOfNodeListMap mapNewNodes;
5053   TElemOfVecOfNnlmiMap mapElemNewNodes;
5054   TElemOfElemListMap newElemsMap;
5055   TIDSortedElemSet::iterator itElem;
5056   double aX, aY, aZ;
5057   int aNb;
5058   SMDSAbs_ElementType aTypeE;
5059   // source elements for each generated one
5060   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5061
5062   // 3. Center of rotation aV0
5063   gp_Pnt aV0 = theRefPoint;
5064   gp_XYZ aGC;
5065   if ( !theHasRefPoint ) {
5066     aNb = 0;
5067     aGC.SetCoord( 0.,0.,0. );
5068
5069     itElem = theElements.begin();
5070     for ( ; itElem != theElements.end(); itElem++ ) {
5071       const SMDS_MeshElement* elem = *itElem;
5072
5073       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5074       while ( itN->more() ) {
5075         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5076         aX = node->X();
5077         aY = node->Y();
5078         aZ = node->Z();
5079
5080         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5081           list<const SMDS_MeshNode*> aLNx;
5082           mapNewNodes[node] = aLNx;
5083           //
5084           gp_XYZ aXYZ( aX, aY, aZ );
5085           aGC += aXYZ;
5086           ++aNb;
5087         }
5088       }
5089     }
5090     aGC /= aNb;
5091     aV0.SetXYZ( aGC );
5092   } // if (!theHasRefPoint) {
5093   mapNewNodes.clear();
5094
5095   // 4. Processing the elements
5096   SMESHDS_Mesh* aMesh = GetMeshDS();
5097
5098   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5099     // check element type
5100     const SMDS_MeshElement* elem = *itElem;
5101     aTypeE = elem->GetType();
5102     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5103       continue;
5104
5105     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5106     newNodesItVec.reserve( elem->NbNodes() );
5107
5108     // loop on elem nodes
5109     int nodeIndex = -1;
5110     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5111     while ( itN->more() )
5112     {
5113       ++nodeIndex;
5114       // check if a node has been already processed
5115       const SMDS_MeshNode* node =
5116         static_cast<const SMDS_MeshNode*>( itN->next() );
5117       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5118       if ( nIt == mapNewNodes.end() ) {
5119         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5120         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5121
5122         // make new nodes
5123         aX = node->X();  aY = node->Y(); aZ = node->Z();
5124
5125         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5126         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5127         gp_Ax1 anAx1, anAxT1T0;
5128         gp_Dir aDT1x, aDT0x, aDT1T0;
5129
5130         aTolAng=1.e-4;
5131
5132         aV0x = aV0;
5133         aPN0.SetCoord(aX, aY, aZ);
5134
5135         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5136         aP0x = aPP0.Pnt();
5137         aDT0x= aPP0.Tangent();
5138         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5139
5140         for ( j = 1; j < aNbTP; ++j ) {
5141           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5142           aP1x = aPP1.Pnt();
5143           aDT1x = aPP1.Tangent();
5144           aAngle1x = aPP1.Angle();
5145
5146           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5147           // Translation
5148           gp_Vec aV01x( aP0x, aP1x );
5149           aTrsf.SetTranslation( aV01x );
5150
5151           // traslated point
5152           aV1x = aV0x.Transformed( aTrsf );
5153           aPN1 = aPN0.Transformed( aTrsf );
5154
5155           // rotation 1 [ T1,T0 ]
5156           aAngleT1T0=-aDT1x.Angle( aDT0x );
5157           if (fabs(aAngleT1T0) > aTolAng) {
5158             aDT1T0=aDT1x^aDT0x;
5159             anAxT1T0.SetLocation( aV1x );
5160             anAxT1T0.SetDirection( aDT1T0 );
5161             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5162
5163             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5164           }
5165
5166           // rotation 2
5167           if ( theHasAngles ) {
5168             anAx1.SetLocation( aV1x );
5169             anAx1.SetDirection( aDT1x );
5170             aTrsfRot.SetRotation( anAx1, aAngle1x );
5171
5172             aPN1 = aPN1.Transformed( aTrsfRot );
5173           }
5174
5175           // make new node
5176           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5177           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5178             // create additional node
5179             double x = ( aPN1.X() + aPN0.X() )/2.;
5180             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5181             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5182             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5183             myLastCreatedNodes.Append(newNode);
5184             srcNodes.Append( node );
5185             listNewNodes.push_back( newNode );
5186           }
5187           aX = aPN1.X();
5188           aY = aPN1.Y();
5189           aZ = aPN1.Z();
5190           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5191           myLastCreatedNodes.Append(newNode);
5192           srcNodes.Append( node );
5193           listNewNodes.push_back( newNode );
5194
5195           aPN0 = aPN1;
5196           aP0x = aP1x;
5197           aV0x = aV1x;
5198           aDT0x = aDT1x;
5199         }
5200       }
5201
5202       else {
5203         // if current elem is quadratic and current node is not medium
5204         // we have to check - may be it is needed to insert additional nodes
5205         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5206           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5207           if(listNewNodes.size()==aNbTP-1) {
5208             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5209             gp_XYZ P(node->X(), node->Y(), node->Z());
5210             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5211             int i;
5212             for(i=0; i<aNbTP-1; i++) {
5213               const SMDS_MeshNode* N = *it;
5214               double x = ( N->X() + P.X() )/2.;
5215               double y = ( N->Y() + P.Y() )/2.;
5216               double z = ( N->Z() + P.Z() )/2.;
5217               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5218               srcNodes.Append( node );
5219               myLastCreatedNodes.Append(newN);
5220               aNodes[2*i] = newN;
5221               aNodes[2*i+1] = N;
5222               P = gp_XYZ(N->X(),N->Y(),N->Z());
5223             }
5224             listNewNodes.clear();
5225             for(i=0; i<2*(aNbTP-1); i++) {
5226               listNewNodes.push_back(aNodes[i]);
5227             }
5228           }
5229         }
5230       }
5231
5232       newNodesItVec.push_back( nIt );
5233     }
5234     // make new elements
5235     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5236     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5237     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5238   }
5239
5240   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5241
5242   if ( theMakeGroups )
5243     generateGroups( srcNodes, srcElems, "extruded");
5244
5245   return EXTR_OK;
5246 }
5247
5248
5249 //=======================================================================
5250 //function : LinearAngleVariation
5251 //purpose  : auxilary for ExtrusionAlongTrack
5252 //=======================================================================
5253 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5254                                             list<double>& Angles)
5255 {
5256   int nbAngles = Angles.size();
5257   if( nbSteps > nbAngles ) {
5258     vector<double> theAngles(nbAngles);
5259     list<double>::iterator it = Angles.begin();
5260     int i = -1;
5261     for(; it!=Angles.end(); it++) {
5262       i++;
5263       theAngles[i] = (*it);
5264     }
5265     list<double> res;
5266     double rAn2St = double( nbAngles ) / double( nbSteps );
5267     double angPrev = 0, angle;
5268     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5269       double angCur = rAn2St * ( iSt+1 );
5270       double angCurFloor  = floor( angCur );
5271       double angPrevFloor = floor( angPrev );
5272       if ( angPrevFloor == angCurFloor )
5273         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5274       else {
5275         int iP = int( angPrevFloor );
5276         double angPrevCeil = ceil(angPrev);
5277         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5278
5279         int iC = int( angCurFloor );
5280         if ( iC < nbAngles )
5281           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5282
5283         iP = int( angPrevCeil );
5284         while ( iC-- > iP )
5285           angle += theAngles[ iC ];
5286       }
5287       res.push_back(angle);
5288       angPrev = angCur;
5289     }
5290     Angles.clear();
5291     it = res.begin();
5292     for(; it!=res.end(); it++)
5293       Angles.push_back( *it );
5294   }
5295 }
5296
5297
5298 //================================================================================
5299 /*!
5300  * \brief Move or copy theElements applying theTrsf to their nodes
5301  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5302  *  \param theTrsf - transformation to apply
5303  *  \param theCopy - if true, create translated copies of theElems
5304  *  \param theMakeGroups - if true and theCopy, create translated groups
5305  *  \param theTargetMesh - mesh to copy translated elements into
5306  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5307  */
5308 //================================================================================
5309
5310 SMESH_MeshEditor::PGroupIDs
5311 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5312                              const gp_Trsf&     theTrsf,
5313                              const bool         theCopy,
5314                              const bool         theMakeGroups,
5315                              SMESH_Mesh*        theTargetMesh)
5316 {
5317   myLastCreatedElems.Clear();
5318   myLastCreatedNodes.Clear();
5319
5320   bool needReverse = false;
5321   string groupPostfix;
5322   switch ( theTrsf.Form() ) {
5323   case gp_PntMirror:
5324     MESSAGE("gp_PntMirror");
5325     needReverse = true;
5326     groupPostfix = "mirrored";
5327     break;
5328   case gp_Ax1Mirror:
5329     MESSAGE("gp_Ax1Mirror");
5330     groupPostfix = "mirrored";
5331     break;
5332   case gp_Ax2Mirror:
5333     MESSAGE("gp_Ax2Mirror");
5334     needReverse = true;
5335     groupPostfix = "mirrored";
5336     break;
5337   case gp_Rotation:
5338     MESSAGE("gp_Rotation");
5339     groupPostfix = "rotated";
5340     break;
5341   case gp_Translation:
5342     MESSAGE("gp_Translation");
5343     groupPostfix = "translated";
5344     break;
5345   case gp_Scale:
5346     MESSAGE("gp_Scale");
5347     groupPostfix = "scaled";
5348     break;
5349   case gp_CompoundTrsf: // different scale by axis
5350     MESSAGE("gp_CompoundTrsf");
5351     groupPostfix = "scaled";
5352     break;
5353   default:
5354     MESSAGE("default");
5355     needReverse = false;
5356     groupPostfix = "transformed";
5357   }
5358
5359   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5360   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5361   SMESHDS_Mesh* aMesh    = GetMeshDS();
5362
5363
5364   // map old node to new one
5365   TNodeNodeMap nodeMap;
5366
5367   // elements sharing moved nodes; those of them which have all
5368   // nodes mirrored but are not in theElems are to be reversed
5369   TIDSortedElemSet inverseElemSet;
5370
5371   // source elements for each generated one
5372   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5373
5374   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5375   TIDSortedElemSet orphanNode;
5376
5377   if ( theElems.empty() ) // transform the whole mesh
5378   {
5379     // add all elements
5380     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5381     while ( eIt->more() ) theElems.insert( eIt->next() );
5382     // add orphan nodes
5383     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5384     while ( nIt->more() )
5385     {
5386       const SMDS_MeshNode* node = nIt->next();
5387       if ( node->NbInverseElements() == 0)
5388         orphanNode.insert( node );
5389     }
5390   }
5391
5392   // loop on elements to transform nodes : first orphan nodes then elems
5393   TIDSortedElemSet::iterator itElem;
5394   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5395   for (int i=0; i<2; i++)
5396   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5397     const SMDS_MeshElement* elem = *itElem;
5398     if ( !elem )
5399       continue;
5400
5401     // loop on elem nodes
5402     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5403     while ( itN->more() ) {
5404
5405       const SMDS_MeshNode* node = cast2Node( itN->next() );
5406       // check if a node has been already transformed
5407       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5408         nodeMap.insert( make_pair ( node, node ));
5409       if ( !n2n_isnew.second )
5410         continue;
5411
5412       double coord[3];
5413       coord[0] = node->X();
5414       coord[1] = node->Y();
5415       coord[2] = node->Z();
5416       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5417       if ( theTargetMesh ) {
5418         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5419         n2n_isnew.first->second = newNode;
5420         myLastCreatedNodes.Append(newNode);
5421         srcNodes.Append( node );
5422       }
5423       else if ( theCopy ) {
5424         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5425         n2n_isnew.first->second = newNode;
5426         myLastCreatedNodes.Append(newNode);
5427         srcNodes.Append( node );
5428       }
5429       else {
5430         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5431         // node position on shape becomes invalid
5432         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5433           ( SMDS_SpacePosition::originSpacePosition() );
5434       }
5435
5436       // keep inverse elements
5437       if ( !theCopy && !theTargetMesh && needReverse ) {
5438         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5439         while ( invElemIt->more() ) {
5440           const SMDS_MeshElement* iel = invElemIt->next();
5441           inverseElemSet.insert( iel );
5442         }
5443       }
5444     }
5445   }
5446
5447   // either create new elements or reverse mirrored ones
5448   if ( !theCopy && !needReverse && !theTargetMesh )
5449     return PGroupIDs();
5450
5451   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5452   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5453     theElems.insert( *invElemIt );
5454
5455   // replicate or reverse elements
5456   // TODO revoir ordre reverse vtk
5457   enum {
5458     REV_TETRA   = 0,  //  = nbNodes - 4
5459     REV_PYRAMID = 1,  //  = nbNodes - 4
5460     REV_PENTA   = 2,  //  = nbNodes - 4
5461     REV_FACE    = 3,
5462     REV_HEXA    = 4,  //  = nbNodes - 4
5463     FORWARD     = 5
5464   };
5465   int index[][8] = {
5466     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5467     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5468     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5469     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5470     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5471     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5472   };
5473
5474   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5475   {
5476     const SMDS_MeshElement* elem = *itElem;
5477     if ( !elem || elem->GetType() == SMDSAbs_Node )
5478       continue;
5479
5480     int nbNodes = elem->NbNodes();
5481     int elemType = elem->GetType();
5482
5483     if (elem->IsPoly()) {
5484       // Polygon or Polyhedral Volume
5485       switch ( elemType ) {
5486       case SMDSAbs_Face:
5487         {
5488           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5489           int iNode = 0;
5490           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5491           while (itN->more()) {
5492             const SMDS_MeshNode* node =
5493               static_cast<const SMDS_MeshNode*>(itN->next());
5494             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5495             if (nodeMapIt == nodeMap.end())
5496               break; // not all nodes transformed
5497             if (needReverse) {
5498               // reverse mirrored faces and volumes
5499               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5500             } else {
5501               poly_nodes[iNode] = (*nodeMapIt).second;
5502             }
5503             iNode++;
5504           }
5505           if ( iNode != nbNodes )
5506             continue; // not all nodes transformed
5507
5508           if ( theTargetMesh ) {
5509             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5510             srcElems.Append( elem );
5511           }
5512           else if ( theCopy ) {
5513             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5514             srcElems.Append( elem );
5515           }
5516           else {
5517             aMesh->ChangePolygonNodes(elem, poly_nodes);
5518           }
5519         }
5520         break;
5521       case SMDSAbs_Volume:
5522         {
5523           // ATTENTION: Reversing is not yet done!!!
5524           const SMDS_VtkVolume* aPolyedre =
5525             dynamic_cast<const SMDS_VtkVolume*>( elem );
5526           if (!aPolyedre) {
5527             MESSAGE("Warning: bad volumic element");
5528             continue;
5529           }
5530
5531           vector<const SMDS_MeshNode*> poly_nodes;
5532           vector<int> quantities;
5533
5534           bool allTransformed = true;
5535           int nbFaces = aPolyedre->NbFaces();
5536           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5537             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5538             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5539               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5540               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5541               if (nodeMapIt == nodeMap.end()) {
5542                 allTransformed = false; // not all nodes transformed
5543               } else {
5544                 poly_nodes.push_back((*nodeMapIt).second);
5545               }
5546             }
5547             quantities.push_back(nbFaceNodes);
5548           }
5549           if ( !allTransformed )
5550             continue; // not all nodes transformed
5551
5552           if ( theTargetMesh ) {
5553             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5554             srcElems.Append( elem );
5555           }
5556           else if ( theCopy ) {
5557             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5558             srcElems.Append( elem );
5559           }
5560           else {
5561             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5562           }
5563         }
5564         break;
5565       default:;
5566       }
5567       continue;
5568     }
5569
5570     // Regular elements
5571     int* i = index[ FORWARD ];
5572     if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5573       if ( elemType == SMDSAbs_Face )
5574         i = index[ REV_FACE ];
5575       else
5576         i = index[ nbNodes - 4 ];
5577     }
5578     if(elem->IsQuadratic()) {
5579       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5580       i = anIds;
5581       if(needReverse) {
5582         if(nbNodes==3) { // quadratic edge
5583           static int anIds[] = {1,0,2};
5584           i = anIds;
5585         }
5586         else if(nbNodes==6) { // quadratic triangle
5587           static int anIds[] = {0,2,1,5,4,3};
5588           i = anIds;
5589         }
5590         else if(nbNodes==8) { // quadratic quadrangle
5591           static int anIds[] = {0,3,2,1,7,6,5,4};
5592           i = anIds;
5593         }
5594         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5595           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5596           i = anIds;
5597         }
5598         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5599           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5600           i = anIds;
5601         }
5602         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5603           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5604           i = anIds;
5605         }
5606         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5607           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5608           i = anIds;
5609         }
5610       }
5611     }
5612
5613     // find transformed nodes
5614     vector<const SMDS_MeshNode*> nodes(nbNodes);
5615     int iNode = 0;
5616     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5617     while ( itN->more() ) {
5618       const SMDS_MeshNode* node =
5619         static_cast<const SMDS_MeshNode*>( itN->next() );
5620       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5621       if ( nodeMapIt == nodeMap.end() )
5622         break; // not all nodes transformed
5623       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5624     }
5625     if ( iNode != nbNodes )
5626       continue; // not all nodes transformed
5627
5628     if ( theTargetMesh ) {
5629       if ( SMDS_MeshElement* copy =
5630            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5631         myLastCreatedElems.Append( copy );
5632         srcElems.Append( elem );
5633       }
5634     }
5635     else if ( theCopy ) {
5636       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5637         srcElems.Append( elem );
5638     }
5639     else {
5640       // reverse element as it was reversed by transformation
5641       if ( nbNodes > 2 )
5642         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5643     }
5644   }
5645
5646   PGroupIDs newGroupIDs;
5647
5648   if ( ( theMakeGroups && theCopy ) ||
5649        ( theMakeGroups && theTargetMesh ) )
5650     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5651
5652   return newGroupIDs;
5653 }
5654
5655
5656 ////=======================================================================
5657 ////function : Scale
5658 ////purpose  :
5659 ////=======================================================================
5660 //
5661 //SMESH_MeshEditor::PGroupIDs
5662 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5663 //                         const gp_Pnt&            thePoint,
5664 //                         const std::list<double>& theScaleFact,
5665 //                         const bool         theCopy,
5666 //                         const bool         theMakeGroups,
5667 //                         SMESH_Mesh*        theTargetMesh)
5668 //{
5669 //  MESSAGE("Scale");
5670 //  myLastCreatedElems.Clear();
5671 //  myLastCreatedNodes.Clear();
5672 //
5673 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5674 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5675 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
5676 //
5677 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5678 //  std::list<double>::const_iterator itS = theScaleFact.begin();
5679 //  scaleX = (*itS);
5680 //  if(theScaleFact.size()==1) {
5681 //    scaleY = (*itS);
5682 //    scaleZ= (*itS);
5683 //  }
5684 //  if(theScaleFact.size()==2) {
5685 //    itS++;
5686 //    scaleY = (*itS);
5687 //    scaleZ= (*itS);
5688 //  }
5689 //  if(theScaleFact.size()>2) {
5690 //    itS++;
5691 //    scaleY = (*itS);
5692 //    itS++;
5693 //    scaleZ= (*itS);
5694 //  }
5695 //
5696 //  // map old node to new one
5697 //  TNodeNodeMap nodeMap;
5698 //
5699 //  // elements sharing moved nodes; those of them which have all
5700 //  // nodes mirrored but are not in theElems are to be reversed
5701 //  TIDSortedElemSet inverseElemSet;
5702 //
5703 //  // source elements for each generated one
5704 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
5705 //
5706 //  // loop on theElems
5707 //  TIDSortedElemSet::iterator itElem;
5708 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5709 //    const SMDS_MeshElement* elem = *itElem;
5710 //    if ( !elem )
5711 //      continue;
5712 //
5713 //    // loop on elem nodes
5714 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5715 //    while ( itN->more() ) {
5716 //
5717 //      // check if a node has been already transformed
5718 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
5719 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5720 //        nodeMap.insert( make_pair ( node, node ));
5721 //      if ( !n2n_isnew.second )
5722 //        continue;
5723 //
5724 //      //double coord[3];
5725 //      //coord[0] = node->X();
5726 //      //coord[1] = node->Y();
5727 //      //coord[2] = node->Z();
5728 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5729 //      double dx = (node->X() - thePoint.X()) * scaleX;
5730 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
5731 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
5732 //      if ( theTargetMesh ) {
5733 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5734 //        const SMDS_MeshNode * newNode =
5735 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5736 //        n2n_isnew.first->second = newNode;
5737 //        myLastCreatedNodes.Append(newNode);
5738 //        srcNodes.Append( node );
5739 //      }
5740 //      else if ( theCopy ) {
5741 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5742 //        const SMDS_MeshNode * newNode =
5743 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5744 //        n2n_isnew.first->second = newNode;
5745 //        myLastCreatedNodes.Append(newNode);
5746 //        srcNodes.Append( node );
5747 //      }
5748 //      else {
5749 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5750 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5751 //        // node position on shape becomes invalid
5752 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
5753 //          ( SMDS_SpacePosition::originSpacePosition() );
5754 //      }
5755 //
5756 //      // keep inverse elements
5757 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
5758 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5759 //      //  while ( invElemIt->more() ) {
5760 //      //    const SMDS_MeshElement* iel = invElemIt->next();
5761 //      //    inverseElemSet.insert( iel );
5762 //      //  }
5763 //      //}
5764 //    }
5765 //  }
5766 //
5767 //  // either create new elements or reverse mirrored ones
5768 //  //if ( !theCopy && !needReverse && !theTargetMesh )
5769 //  if ( !theCopy && !theTargetMesh )
5770 //    return PGroupIDs();
5771 //
5772 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5773 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5774 //    theElems.insert( *invElemIt );
5775 //
5776 //  // replicate or reverse elements
5777 //
5778 //  enum {
5779 //    REV_TETRA   = 0,  //  = nbNodes - 4
5780 //    REV_PYRAMID = 1,  //  = nbNodes - 4
5781 //    REV_PENTA   = 2,  //  = nbNodes - 4
5782 //    REV_FACE    = 3,
5783 //    REV_HEXA    = 4,  //  = nbNodes - 4
5784 //    FORWARD     = 5
5785 //  };
5786 //  int index[][8] = {
5787 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5788 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5789 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5790 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5791 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5792 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5793 //  };
5794 //
5795 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5796 //  {
5797 //    const SMDS_MeshElement* elem = *itElem;
5798 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
5799 //      continue;
5800 //
5801 //    int nbNodes = elem->NbNodes();
5802 //    int elemType = elem->GetType();
5803 //
5804 //    if (elem->IsPoly()) {
5805 //      // Polygon or Polyhedral Volume
5806 //      switch ( elemType ) {
5807 //      case SMDSAbs_Face:
5808 //        {
5809 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5810 //          int iNode = 0;
5811 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5812 //          while (itN->more()) {
5813 //            const SMDS_MeshNode* node =
5814 //              static_cast<const SMDS_MeshNode*>(itN->next());
5815 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5816 //            if (nodeMapIt == nodeMap.end())
5817 //              break; // not all nodes transformed
5818 //            //if (needReverse) {
5819 //            //  // reverse mirrored faces and volumes
5820 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5821 //            //} else {
5822 //            poly_nodes[iNode] = (*nodeMapIt).second;
5823 //            //}
5824 //            iNode++;
5825 //          }
5826 //          if ( iNode != nbNodes )
5827 //            continue; // not all nodes transformed
5828 //
5829 //          if ( theTargetMesh ) {
5830 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5831 //            srcElems.Append( elem );
5832 //          }
5833 //          else if ( theCopy ) {
5834 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5835 //            srcElems.Append( elem );
5836 //          }
5837 //          else {
5838 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
5839 //          }
5840 //        }
5841 //        break;
5842 //      case SMDSAbs_Volume:
5843 //        {
5844 //          // ATTENTION: Reversing is not yet done!!!
5845 //          const SMDS_VtkVolume* aPolyedre =
5846 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
5847 //          if (!aPolyedre) {
5848 //            MESSAGE("Warning: bad volumic element");
5849 //            continue;
5850 //          }
5851 //
5852 //          vector<const SMDS_MeshNode*> poly_nodes;
5853 //          vector<int> quantities;
5854 //
5855 //          bool allTransformed = true;
5856 //          int nbFaces = aPolyedre->NbFaces();
5857 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5858 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5859 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5860 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5861 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5862 //              if (nodeMapIt == nodeMap.end()) {
5863 //                allTransformed = false; // not all nodes transformed
5864 //              } else {
5865 //                poly_nodes.push_back((*nodeMapIt).second);
5866 //              }
5867 //            }
5868 //            quantities.push_back(nbFaceNodes);
5869 //          }
5870 //          if ( !allTransformed )
5871 //            continue; // not all nodes transformed
5872 //
5873 //          if ( theTargetMesh ) {
5874 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5875 //            srcElems.Append( elem );
5876 //          }
5877 //          else if ( theCopy ) {
5878 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5879 //            srcElems.Append( elem );
5880 //          }
5881 //          else {
5882 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5883 //          }
5884 //        }
5885 //        break;
5886 //      default:;
5887 //      }
5888 //      continue;
5889 //    }
5890 //
5891 //    // Regular elements
5892 //    int* i = index[ FORWARD ];
5893 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5894 //    //  if ( elemType == SMDSAbs_Face )
5895 //    //    i = index[ REV_FACE ];
5896 //    //  else
5897 //    //    i = index[ nbNodes - 4 ];
5898 //
5899 //    if(elem->IsQuadratic()) {
5900 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5901 //      i = anIds;
5902 //      //if(needReverse) {
5903 //      //  if(nbNodes==3) { // quadratic edge
5904 //      //    static int anIds[] = {1,0,2};
5905 //      //    i = anIds;
5906 //      //  }
5907 //      //  else if(nbNodes==6) { // quadratic triangle
5908 //      //    static int anIds[] = {0,2,1,5,4,3};
5909 //      //    i = anIds;
5910 //      //  }
5911 //      //  else if(nbNodes==8) { // quadratic quadrangle
5912 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
5913 //      //    i = anIds;
5914 //      //  }
5915 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5916 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5917 //      //    i = anIds;
5918 //      //  }
5919 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5920 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5921 //      //    i = anIds;
5922 //      //  }
5923 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5924 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5925 //      //    i = anIds;
5926 //      //  }
5927 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5928 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5929 //      //    i = anIds;
5930 //      //  }
5931 //      //}
5932 //    }
5933 //
5934 //    // find transformed nodes
5935 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
5936 //    int iNode = 0;
5937 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5938 //    while ( itN->more() ) {
5939 //      const SMDS_MeshNode* node =
5940 //        static_cast<const SMDS_MeshNode*>( itN->next() );
5941 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5942 //      if ( nodeMapIt == nodeMap.end() )
5943 //        break; // not all nodes transformed
5944 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5945 //    }
5946 //    if ( iNode != nbNodes )
5947 //      continue; // not all nodes transformed
5948 //
5949 //    if ( theTargetMesh ) {
5950 //      if ( SMDS_MeshElement* copy =
5951 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5952 //        myLastCreatedElems.Append( copy );
5953 //        srcElems.Append( elem );
5954 //      }
5955 //    }
5956 //    else if ( theCopy ) {
5957 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5958 //        myLastCreatedElems.Append( copy );
5959 //        srcElems.Append( elem );
5960 //      }
5961 //    }
5962 //    else {
5963 //      // reverse element as it was reversed by transformation
5964 //      if ( nbNodes > 2 )
5965 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5966 //    }
5967 //  }
5968 //
5969 //  PGroupIDs newGroupIDs;
5970 //
5971 //  if ( theMakeGroups && theCopy ||
5972 //       theMakeGroups && theTargetMesh ) {
5973 //    string groupPostfix = "scaled";
5974 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5975 //  }
5976 //
5977 //  return newGroupIDs;
5978 //}
5979
5980
5981 //=======================================================================
5982 /*!
5983  * \brief Create groups of elements made during transformation
5984  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5985  * \param elemGens - elements making corresponding myLastCreatedElems
5986  * \param postfix - to append to names of new groups
5987  */
5988 //=======================================================================
5989
5990 SMESH_MeshEditor::PGroupIDs
5991 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5992                                  const SMESH_SequenceOfElemPtr& elemGens,
5993                                  const std::string&             postfix,
5994                                  SMESH_Mesh*                    targetMesh)
5995 {
5996   PGroupIDs newGroupIDs( new list<int> );
5997   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5998
5999   // Sort existing groups by types and collect their names
6000
6001   // to store an old group and a generated new one
6002   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6003   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6004   // group names
6005   set< string > groupNames;
6006   //
6007   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6008   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6009   while ( groupIt->more() ) {
6010     SMESH_Group * group = groupIt->next();
6011     if ( !group ) continue;
6012     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6013     if ( !groupDS || groupDS->IsEmpty() ) continue;
6014     groupNames.insert( group->GetName() );
6015     groupDS->SetStoreName( group->GetName() );
6016     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6017   }
6018
6019   // Groups creation
6020
6021   // loop on nodes and elements
6022   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6023   {
6024     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6025     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6026     if ( gens.Length() != elems.Length() )
6027       throw SALOME_Exception(LOCALIZED("invalid args"));
6028
6029     // loop on created elements
6030     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6031     {
6032       const SMDS_MeshElement* sourceElem = gens( iElem );
6033       if ( !sourceElem ) {
6034         MESSAGE("generateGroups(): NULL source element");
6035         continue;
6036       }
6037       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6038       if ( groupsOldNew.empty() ) {
6039         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6040           ++iElem; // skip all elements made by sourceElem
6041         continue;
6042       }
6043       // collect all elements made by sourceElem
6044       list< const SMDS_MeshElement* > resultElems;
6045       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6046         if ( resElem != sourceElem )
6047           resultElems.push_back( resElem );
6048       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6049         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6050           if ( resElem != sourceElem )
6051             resultElems.push_back( resElem );
6052       // do not generate element groups from node ones
6053       if ( sourceElem->GetType() == SMDSAbs_Node &&
6054            elems( iElem )->GetType() != SMDSAbs_Node )
6055         continue;
6056
6057       // add resultElems to groups made by ones the sourceElem belongs to
6058       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6059       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6060       {
6061         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6062         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6063         {
6064           SMDS_MeshGroup* & newGroup = gOldNew->second;
6065           if ( !newGroup )// create a new group
6066           {
6067             // make a name
6068             string name = oldGroup->GetStoreName();
6069             if ( !targetMesh ) {
6070               name += "_";
6071               name += postfix;
6072               int nb = 0;
6073               while ( !groupNames.insert( name ).second ) // name exists
6074               {
6075                 if ( nb == 0 ) {
6076                   name += "_1";
6077                 }
6078                 else {
6079                   TCollection_AsciiString nbStr(nb+1);
6080                   name.resize( name.rfind('_')+1 );
6081                   name += nbStr.ToCString();
6082                 }
6083                 ++nb;
6084               }
6085             }
6086             // make a group
6087             int id;
6088             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6089                                                  name.c_str(), id );
6090             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6091             newGroup = & groupDS->SMDSGroup();
6092             newGroupIDs->push_back( id );
6093           }
6094
6095           // fill in a new group
6096           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6097           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6098             newGroup->Add( *resElemIt );
6099         }
6100       }
6101     } // loop on created elements
6102   }// loop on nodes and elements
6103
6104   return newGroupIDs;
6105 }
6106
6107 //================================================================================
6108 /*!
6109  * \brief Return list of group of nodes close to each other within theTolerance
6110  *        Search among theNodes or in the whole mesh if theNodes is empty using
6111  *        an Octree algorithm
6112  */
6113 //================================================================================
6114
6115 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6116                                             const double         theTolerance,
6117                                             TListOfListOfNodes & theGroupsOfNodes)
6118 {
6119   myLastCreatedElems.Clear();
6120   myLastCreatedNodes.Clear();
6121
6122   if ( theNodes.empty() )
6123   { // get all nodes in the mesh
6124     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6125     while ( nIt->more() )
6126       theNodes.insert( theNodes.end(),nIt->next());
6127   }
6128
6129   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6130 }
6131
6132
6133 //=======================================================================
6134 /*!
6135  * \brief Implementation of search for the node closest to point
6136  */
6137 //=======================================================================
6138
6139 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6140 {
6141   //---------------------------------------------------------------------
6142   /*!
6143    * \brief Constructor
6144    */
6145   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6146   {
6147     myMesh = ( SMESHDS_Mesh* ) theMesh;
6148
6149     TIDSortedNodeSet nodes;
6150     if ( theMesh ) {
6151       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6152       while ( nIt->more() )
6153         nodes.insert( nodes.end(), nIt->next() );
6154     }
6155     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6156
6157     // get max size of a leaf box
6158     SMESH_OctreeNode* tree = myOctreeNode;
6159     while ( !tree->isLeaf() )
6160     {
6161       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6162       if ( cIt->more() )
6163         tree = cIt->next();
6164     }
6165     myHalfLeafSize = tree->maxSize() / 2.;
6166   }
6167
6168   //---------------------------------------------------------------------
6169   /*!
6170    * \brief Move node and update myOctreeNode accordingly
6171    */
6172   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6173   {
6174     myOctreeNode->UpdateByMoveNode( node, toPnt );
6175     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6176   }
6177
6178   //---------------------------------------------------------------------
6179   /*!
6180    * \brief Do it's job
6181    */
6182   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6183   {
6184     map<double, const SMDS_MeshNode*> dist2Nodes;
6185     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6186     if ( !dist2Nodes.empty() )
6187       return dist2Nodes.begin()->second;
6188     list<const SMDS_MeshNode*> nodes;
6189     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6190
6191     double minSqDist = DBL_MAX;
6192     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6193     {
6194       // sort leafs by their distance from thePnt
6195       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6196       TDistTreeMap treeMap;
6197       list< SMESH_OctreeNode* > treeList;
6198       list< SMESH_OctreeNode* >::iterator trIt;
6199       treeList.push_back( myOctreeNode );
6200
6201       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6202       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6203       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6204       {
6205         SMESH_OctreeNode* tree = *trIt;
6206         if ( !tree->isLeaf() ) // put children to the queue
6207         {
6208           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6209           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6210           while ( cIt->more() )
6211             treeList.push_back( cIt->next() );
6212         }
6213         else if ( tree->NbNodes() ) // put a tree to the treeMap
6214         {
6215           const Bnd_B3d& box = tree->getBox();
6216           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6217           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6218           if ( !it_in.second ) // not unique distance to box center
6219             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6220         }
6221       }
6222       // find distance after which there is no sense to check tree's
6223       double sqLimit = DBL_MAX;
6224       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6225       if ( treeMap.size() > 5 ) {
6226         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6227         const Bnd_B3d& box = closestTree->getBox();
6228         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6229         sqLimit = limit * limit;
6230       }
6231       // get all nodes from trees
6232       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6233         if ( sqDist_tree->first > sqLimit )
6234           break;
6235         SMESH_OctreeNode* tree = sqDist_tree->second;
6236         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6237       }
6238     }
6239     // find closest among nodes
6240     minSqDist = DBL_MAX;
6241     const SMDS_MeshNode* closestNode = 0;
6242     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6243     for ( ; nIt != nodes.end(); ++nIt ) {
6244       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6245       if ( minSqDist > sqDist ) {
6246         closestNode = *nIt;
6247         minSqDist = sqDist;
6248       }
6249     }
6250     return closestNode;
6251   }
6252
6253   //---------------------------------------------------------------------
6254   /*!
6255    * \brief Destructor
6256    */
6257   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6258
6259   //---------------------------------------------------------------------
6260   /*!
6261    * \brief Return the node tree
6262    */
6263   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6264
6265 private:
6266   SMESH_OctreeNode* myOctreeNode;
6267   SMESHDS_Mesh*     myMesh;
6268   double            myHalfLeafSize; // max size of a leaf box
6269 };
6270
6271 //=======================================================================
6272 /*!
6273  * \brief Return SMESH_NodeSearcher
6274  */
6275 //=======================================================================
6276
6277 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6278 {
6279   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6280 }
6281
6282 // ========================================================================
6283 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6284 {
6285   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6286   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6287   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6288
6289   //=======================================================================
6290   /*!
6291    * \brief Octal tree of bounding boxes of elements
6292    */
6293   //=======================================================================
6294
6295   class ElementBndBoxTree : public SMESH_Octree
6296   {
6297   public:
6298
6299     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6300     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6301     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6302     ~ElementBndBoxTree();
6303
6304   protected:
6305     ElementBndBoxTree() {}
6306     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6307     void buildChildrenData();
6308     Bnd_B3d* buildRootBox();
6309   private:
6310     //!< Bounding box of element
6311     struct ElementBox : public Bnd_B3d
6312     {
6313       const SMDS_MeshElement* _element;
6314       int                     _refCount; // an ElementBox can be included in several tree branches
6315       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6316     };
6317     vector< ElementBox* > _elements;
6318   };
6319
6320   //================================================================================
6321   /*!
6322    * \brief ElementBndBoxTree creation
6323    */
6324   //================================================================================
6325
6326   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6327     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6328   {
6329     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6330     _elements.reserve( nbElems );
6331
6332     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6333     while ( elemIt->more() )
6334       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6335
6336     if ( _elements.size() > MaxNbElemsInLeaf )
6337       compute();
6338     else
6339       myIsLeaf = true;
6340   }
6341
6342   //================================================================================
6343   /*!
6344    * \brief Destructor
6345    */
6346   //================================================================================
6347
6348   ElementBndBoxTree::~ElementBndBoxTree()
6349   {
6350     for ( int i = 0; i < _elements.size(); ++i )
6351       if ( --_elements[i]->_refCount <= 0 )
6352         delete _elements[i];
6353   }
6354
6355   //================================================================================
6356   /*!
6357    * \brief Return the maximal box
6358    */
6359   //================================================================================
6360
6361   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6362   {
6363     Bnd_B3d* box = new Bnd_B3d;
6364     for ( int i = 0; i < _elements.size(); ++i )
6365       box->Add( *_elements[i] );
6366     return box;
6367   }
6368
6369   //================================================================================
6370   /*!
6371    * \brief Redistrubute element boxes among children
6372    */
6373   //================================================================================
6374
6375   void ElementBndBoxTree::buildChildrenData()
6376   {
6377     for ( int i = 0; i < _elements.size(); ++i )
6378     {
6379       for (int j = 0; j < 8; j++)
6380       {
6381         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6382         {
6383           _elements[i]->_refCount++;
6384           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6385         }
6386       }
6387       _elements[i]->_refCount--;
6388     }
6389     _elements.clear();
6390
6391     for (int j = 0; j < 8; j++)
6392     {
6393       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6394       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6395         child->myIsLeaf = true;
6396
6397       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6398         child->_elements.resize( child->_elements.size() ); // compact
6399     }
6400   }
6401
6402   //================================================================================
6403   /*!
6404    * \brief Return elements which can include the point
6405    */
6406   //================================================================================
6407
6408   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6409                                                 TIDSortedElemSet& foundElems)
6410   {
6411     if ( level() && getBox().IsOut( point.XYZ() ))
6412       return;
6413
6414     if ( isLeaf() )
6415     {
6416       for ( int i = 0; i < _elements.size(); ++i )
6417         if ( !_elements[i]->IsOut( point.XYZ() ))
6418           foundElems.insert( _elements[i]->_element );
6419     }
6420     else
6421     {
6422       for (int i = 0; i < 8; i++)
6423         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6424     }
6425   }
6426
6427   //================================================================================
6428   /*!
6429    * \brief Return elements which can be intersected by the line
6430    */
6431   //================================================================================
6432
6433   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6434                                                TIDSortedElemSet& foundElems)
6435   {
6436     if ( level() && getBox().IsOut( line ))
6437       return;
6438
6439     if ( isLeaf() )
6440     {
6441       for ( int i = 0; i < _elements.size(); ++i )
6442         if ( !_elements[i]->IsOut( line ))
6443           foundElems.insert( _elements[i]->_element );
6444     }
6445     else
6446     {
6447       for (int i = 0; i < 8; i++)
6448         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6449     }
6450   }
6451
6452   //================================================================================
6453   /*!
6454    * \brief Construct the element box
6455    */
6456   //================================================================================
6457
6458   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6459   {
6460     _element  = elem;
6461     _refCount = 1;
6462     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6463     while ( nIt->more() )
6464       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6465     Enlarge( tolerance );
6466   }
6467
6468 } // namespace
6469
6470 //=======================================================================
6471 /*!
6472  * \brief Implementation of search for the elements by point and
6473  *        of classification of point in 2D mesh
6474  */
6475 //=======================================================================
6476
6477 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6478 {
6479   SMESHDS_Mesh*                _mesh;
6480   SMDS_ElemIteratorPtr         _meshPartIt;
6481   ElementBndBoxTree*           _ebbTree;
6482   SMESH_NodeSearcherImpl*      _nodeSearcher;
6483   SMDSAbs_ElementType          _elementType;
6484   double                       _tolerance;
6485   bool                         _outerFacesFound;
6486   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6487
6488   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6489     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6490   ~SMESH_ElementSearcherImpl()
6491   {
6492     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6493     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6494   }
6495   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6496                                   SMDSAbs_ElementType                type,
6497                                   vector< const SMDS_MeshElement* >& foundElements);
6498   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6499
6500   void GetElementsNearLine( const gp_Ax1&                      line,
6501                             SMDSAbs_ElementType                type,
6502                             vector< const SMDS_MeshElement* >& foundElems);
6503   double getTolerance();
6504   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6505                             const double tolerance, double & param);
6506   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6507   bool isOuterBoundary(const SMDS_MeshElement* face) const
6508   {
6509     return _outerFaces.empty() || _outerFaces.count(face);
6510   }
6511   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6512   {
6513     const SMDS_MeshElement* _face;
6514     gp_Vec                  _faceNorm;
6515     bool                    _coincides; //!< the line lays in face plane
6516     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6517       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6518   };
6519   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6520   {
6521     SMESH_TLink      _link;
6522     TIDSortedElemSet _faces;
6523     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6524       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6525   };
6526 };
6527
6528 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6529 {
6530   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6531              << ", _coincides="<<i._coincides << ")";
6532 }
6533
6534 //=======================================================================
6535 /*!
6536  * \brief define tolerance for search
6537  */
6538 //=======================================================================
6539
6540 double SMESH_ElementSearcherImpl::getTolerance()
6541 {
6542   if ( _tolerance < 0 )
6543   {
6544     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6545
6546     _tolerance = 0;
6547     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6548     {
6549       double boxSize = _nodeSearcher->getTree()->maxSize();
6550       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6551     }
6552     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6553     {
6554       double boxSize = _ebbTree->maxSize();
6555       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6556     }
6557     if ( _tolerance == 0 )
6558     {
6559       // define tolerance by size of a most complex element
6560       int complexType = SMDSAbs_Volume;
6561       while ( complexType > SMDSAbs_All &&
6562               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6563         --complexType;
6564       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6565       double elemSize;
6566       if ( complexType == int( SMDSAbs_Node ))
6567       {
6568         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6569         elemSize = 1;
6570         if ( meshInfo.NbNodes() > 2 )
6571           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6572       }
6573       else
6574       {
6575         SMDS_ElemIteratorPtr elemIt =
6576             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6577         const SMDS_MeshElement* elem = elemIt->next();
6578         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6579         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6580         elemSize = 0;
6581         while ( nodeIt->more() )
6582         {
6583           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6584           elemSize = max( dist, elemSize );
6585         }
6586       }
6587       _tolerance = 1e-4 * elemSize;
6588     }
6589   }
6590   return _tolerance;
6591 }
6592
6593 //================================================================================
6594 /*!
6595  * \brief Find intersection of the line and an edge of face and return parameter on line
6596  */
6597 //================================================================================
6598
6599 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6600                                                      const SMDS_MeshElement* face,
6601                                                      const double            tol,
6602                                                      double &                param)
6603 {
6604   int nbInts = 0;
6605   param = 0;
6606
6607   GeomAPI_ExtremaCurveCurve anExtCC;
6608   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6609   
6610   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6611   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6612   {
6613     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6614                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6615     anExtCC.Init( lineCurve, edge);
6616     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6617     {
6618       Quantity_Parameter pl, pe;
6619       anExtCC.LowerDistanceParameters( pl, pe );
6620       param += pl;
6621       if ( ++nbInts == 2 )
6622         break;
6623     }
6624   }
6625   if ( nbInts > 0 ) param /= nbInts;
6626   return nbInts > 0;
6627 }
6628 //================================================================================
6629 /*!
6630  * \brief Find all faces belonging to the outer boundary of mesh
6631  */
6632 //================================================================================
6633
6634 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6635 {
6636   if ( _outerFacesFound ) return;
6637
6638   // Collect all outer faces by passing from one outer face to another via their links
6639   // and BTW find out if there are internal faces at all.
6640
6641   // checked links and links where outer boundary meets internal one
6642   set< SMESH_TLink > visitedLinks, seamLinks;
6643
6644   // links to treat with already visited faces sharing them
6645   list < TFaceLink > startLinks;
6646
6647   // load startLinks with the first outerFace
6648   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6649   _outerFaces.insert( outerFace );
6650
6651   TIDSortedElemSet emptySet;
6652   while ( !startLinks.empty() )
6653   {
6654     const SMESH_TLink& link  = startLinks.front()._link;
6655     TIDSortedElemSet&  faces = startLinks.front()._faces;
6656
6657     outerFace = *faces.begin();
6658     // find other faces sharing the link
6659     const SMDS_MeshElement* f;
6660     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6661       faces.insert( f );
6662
6663     // select another outer face among the found 
6664     const SMDS_MeshElement* outerFace2 = 0;
6665     if ( faces.size() == 2 )
6666     {
6667       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6668     }
6669     else if ( faces.size() > 2 )
6670     {
6671       seamLinks.insert( link );
6672
6673       // link direction within the outerFace
6674       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6675                    SMESH_TNodeXYZ( link.node2()));
6676       int i1 = outerFace->GetNodeIndex( link.node1() );
6677       int i2 = outerFace->GetNodeIndex( link.node2() );
6678       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6679       if ( rev ) n1n2.Reverse();
6680       // outerFace normal
6681       gp_XYZ ofNorm, fNorm;
6682       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6683       {
6684         // direction from the link inside outerFace
6685         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6686         // sort all other faces by angle with the dirInOF
6687         map< double, const SMDS_MeshElement* > angle2Face;
6688         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6689         for ( ; face != faces.end(); ++face )
6690         {
6691           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6692             continue;
6693           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6694           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6695           if ( angle < 0 ) angle += 2*PI;
6696           angle2Face.insert( make_pair( angle, *face ));
6697         }
6698         if ( !angle2Face.empty() )
6699           outerFace2 = angle2Face.begin()->second;
6700       }
6701     }
6702     // store the found outer face and add its links to continue seaching from
6703     if ( outerFace2 )
6704     {
6705       _outerFaces.insert( outerFace );
6706       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6707       for ( int i = 0; i < nbNodes; ++i )
6708       {
6709         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6710         if ( visitedLinks.insert( link2 ).second )
6711           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6712       }
6713     }
6714     startLinks.pop_front();
6715   }
6716   _outerFacesFound = true;
6717
6718   if ( !seamLinks.empty() )
6719   {
6720     // There are internal boundaries touching the outher one,
6721     // find all faces of internal boundaries in order to find
6722     // faces of boundaries of holes, if any.
6723     
6724   }
6725   else
6726   {
6727     _outerFaces.clear();
6728   }
6729 }
6730
6731 //=======================================================================
6732 /*!
6733  * \brief Find elements of given type where the given point is IN or ON.
6734  *        Returns nb of found elements and elements them-selves.
6735  *
6736  * 'ALL' type means elements of any type excluding nodes and 0D elements
6737  */
6738 //=======================================================================
6739
6740 int SMESH_ElementSearcherImpl::
6741 FindElementsByPoint(const gp_Pnt&                      point,
6742                     SMDSAbs_ElementType                type,
6743                     vector< const SMDS_MeshElement* >& foundElements)
6744 {
6745   foundElements.clear();
6746
6747   double tolerance = getTolerance();
6748
6749   // =================================================================================
6750   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6751   {
6752     if ( !_nodeSearcher )
6753       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6754
6755     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6756     if ( !closeNode ) return foundElements.size();
6757
6758     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6759       return foundElements.size(); // to far from any node
6760
6761     if ( type == SMDSAbs_Node )
6762     {
6763       foundElements.push_back( closeNode );
6764     }
6765     else
6766     {
6767       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6768       while ( elemIt->more() )
6769         foundElements.push_back( elemIt->next() );
6770     }
6771   }
6772   // =================================================================================
6773   else // elements more complex than 0D
6774   {
6775     if ( !_ebbTree || _elementType != type )
6776     {
6777       if ( _ebbTree ) delete _ebbTree;
6778       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6779     }
6780     TIDSortedElemSet suspectElems;
6781     _ebbTree->getElementsNearPoint( point, suspectElems );
6782     TIDSortedElemSet::iterator elem = suspectElems.begin();
6783     for ( ; elem != suspectElems.end(); ++elem )
6784       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6785         foundElements.push_back( *elem );
6786   }
6787   return foundElements.size();
6788 }
6789
6790 //================================================================================
6791 /*!
6792  * \brief Classify the given point in the closed 2D mesh
6793  */
6794 //================================================================================
6795
6796 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6797 {
6798   double tolerance = getTolerance();
6799   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6800   {
6801     if ( _ebbTree ) delete _ebbTree;
6802     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6803   }
6804   // Algo: analyse transition of a line starting at the point through mesh boundary;
6805   // try three lines parallel to axis of the coordinate system and perform rough
6806   // analysis. If solution is not clear perform thorough analysis.
6807
6808   const int nbAxes = 3;
6809   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6810   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6811   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6812   multimap< int, int > nbInt2Axis; // to find the simplest case
6813   for ( int axis = 0; axis < nbAxes; ++axis )
6814   {
6815     gp_Ax1 lineAxis( point, axisDir[axis]);
6816     gp_Lin line    ( lineAxis );
6817
6818     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6819     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6820
6821     // Intersect faces with the line
6822
6823     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6824     TIDSortedElemSet::iterator face = suspectFaces.begin();
6825     for ( ; face != suspectFaces.end(); ++face )
6826     {
6827       // get face plane
6828       gp_XYZ fNorm;
6829       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6830       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6831
6832       // perform intersection
6833       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6834       if ( !intersection.IsDone() )
6835         continue;
6836       if ( intersection.IsInQuadric() )
6837       {
6838         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6839       }
6840       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6841       {
6842         gp_Pnt intersectionPoint = intersection.Point(1);
6843         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6844           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6845       }
6846     }
6847     // Analyse intersections roughly
6848
6849     int nbInter = u2inters.size();
6850     if ( nbInter == 0 )
6851       return TopAbs_OUT; 
6852
6853     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6854     if ( nbInter == 1 ) // not closed mesh
6855       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6856
6857     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6858       return TopAbs_ON;
6859
6860     if ( (f<0) == (l<0) )
6861       return TopAbs_OUT;
6862
6863     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6864     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6865     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6866       return TopAbs_IN;
6867
6868     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6869
6870     if ( _outerFacesFound ) break; // pass to thorough analysis
6871
6872   } // three attempts - loop on CS axes
6873
6874   // Analyse intersections thoroughly.
6875   // We make two loops maximum, on the first one we only exclude touching intersections,
6876   // on the second, if situation is still unclear, we gather and use information on
6877   // position of faces (internal or outer). If faces position is already gathered,
6878   // we make the second loop right away.
6879
6880   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6881   {
6882     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6883     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6884     {
6885       int axis = nb_axis->second;
6886       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6887
6888       gp_Ax1 lineAxis( point, axisDir[axis]);
6889       gp_Lin line    ( lineAxis );
6890
6891       // add tangent intersections to u2inters
6892       double param;
6893       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6894       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6895         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6896           u2inters.insert(make_pair( param, *tgtInt ));
6897       tangentInters[ axis ].clear();
6898
6899       // Count intersections before and after the point excluding touching ones.
6900       // If hasPositionInfo we count intersections of outer boundary only
6901
6902       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6903       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6904       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6905       bool ok = ! u_int1->second._coincides;
6906       while ( ok && u_int1 != u2inters.end() )
6907       {
6908         double u = u_int1->first;
6909         bool touchingInt = false;
6910         if ( ++u_int2 != u2inters.end() )
6911         {
6912           // skip intersections at the same point (if the line passes through edge or node)
6913           int nbSamePnt = 0;
6914           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6915           {
6916             ++nbSamePnt;
6917             ++u_int2;
6918           }
6919
6920           // skip tangent intersections
6921           int nbTgt = 0;
6922           const SMDS_MeshElement* prevFace = u_int1->second._face;
6923           while ( ok && u_int2->second._coincides )
6924           {
6925             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6926               ok = false;
6927             else
6928             {
6929               nbTgt++;
6930               u_int2++;
6931               ok = ( u_int2 != u2inters.end() );
6932             }
6933           }
6934           if ( !ok ) break;
6935
6936           // skip intersections at the same point after tangent intersections
6937           if ( nbTgt > 0 )
6938           {
6939             double u2 = u_int2->first;
6940             ++u_int2;
6941             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6942             {
6943               ++nbSamePnt;
6944               ++u_int2;
6945             }
6946           }
6947           // decide if we skipped a touching intersection
6948           if ( nbSamePnt + nbTgt > 0 )
6949           {
6950             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6951             map< double, TInters >::iterator u_int = u_int1;
6952             for ( ; u_int != u_int2; ++u_int )
6953             {
6954               if ( u_int->second._coincides ) continue;
6955               double dot = u_int->second._faceNorm * line.Direction();
6956               if ( dot > maxDot ) maxDot = dot;
6957               if ( dot < minDot ) minDot = dot;
6958             }
6959             touchingInt = ( minDot*maxDot < 0 );
6960           }
6961         }
6962         if ( !touchingInt )
6963         {
6964           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6965           {
6966             if ( u < 0 )
6967               ++nbIntBeforePoint;
6968             else
6969               ++nbIntAfterPoint;
6970           }
6971           if ( u < f ) f = u;
6972           if ( u > l ) l = u;
6973         }
6974
6975         u_int1 = u_int2; // to next intersection
6976
6977       } // loop on intersections with one line
6978
6979       if ( ok )
6980       {
6981         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6982           return TopAbs_ON;
6983
6984         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6985           return TopAbs_OUT; 
6986
6987         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6988           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6989
6990         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6991           return TopAbs_IN;
6992
6993         if ( (f<0) == (l<0) )
6994           return TopAbs_OUT;
6995
6996         if ( hasPositionInfo )
6997           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6998       }
6999     } // loop on intersections of the tree lines - thorough analysis
7000
7001     if ( !hasPositionInfo )
7002     {
7003       // gather info on faces position - is face in the outer boundary or not
7004       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7005       findOuterBoundary( u2inters.begin()->second._face );
7006     }
7007
7008   } // two attempts - with and w/o faces position info in the mesh
7009
7010   return TopAbs_UNKNOWN;
7011 }
7012
7013 //=======================================================================
7014 /*!
7015  * \brief Return elements possibly intersecting the line
7016  */
7017 //=======================================================================
7018
7019 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7020                                                      SMDSAbs_ElementType                type,
7021                                                      vector< const SMDS_MeshElement* >& foundElems)
7022 {
7023   if ( !_ebbTree || _elementType != type )
7024   {
7025     if ( _ebbTree ) delete _ebbTree;
7026     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7027   }
7028   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7029   _ebbTree->getElementsNearLine( line, suspectFaces );
7030   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7031 }
7032
7033 //=======================================================================
7034 /*!
7035  * \brief Return SMESH_ElementSearcher
7036  */
7037 //=======================================================================
7038
7039 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7040 {
7041   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7042 }
7043
7044 //=======================================================================
7045 /*!
7046  * \brief Return SMESH_ElementSearcher
7047  */
7048 //=======================================================================
7049
7050 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7051 {
7052   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7053 }
7054
7055 //=======================================================================
7056 /*!
7057  * \brief Return true if the point is IN or ON of the element
7058  */
7059 //=======================================================================
7060
7061 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7062 {
7063   if ( element->GetType() == SMDSAbs_Volume)
7064   {
7065     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7066   }
7067
7068   // get ordered nodes
7069
7070   vector< gp_XYZ > xyz;
7071   vector<const SMDS_MeshNode*> nodeList;
7072
7073   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7074   if ( element->IsQuadratic() ) {
7075     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7076       nodeIt = f->interlacedNodesElemIterator();
7077     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7078       nodeIt = e->interlacedNodesElemIterator();
7079   }
7080   while ( nodeIt->more() )
7081     {
7082       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7083       xyz.push_back( SMESH_TNodeXYZ(node) );
7084       nodeList.push_back(node);
7085     }
7086
7087   int i, nbNodes = element->NbNodes();
7088
7089   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7090   {
7091     // compute face normal
7092     gp_Vec faceNorm(0,0,0);
7093     xyz.push_back( xyz.front() );
7094     nodeList.push_back( nodeList.front() );
7095     for ( i = 0; i < nbNodes; ++i )
7096     {
7097       gp_Vec edge1( xyz[i+1], xyz[i]);
7098       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7099       faceNorm += edge1 ^ edge2;
7100     }
7101     double normSize = faceNorm.Magnitude();
7102     if ( normSize <= tol )
7103     {
7104       // degenerated face: point is out if it is out of all face edges
7105       for ( i = 0; i < nbNodes; ++i )
7106       {
7107         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7108         if ( !isOut( &edge, point, tol ))
7109           return false;
7110       }
7111       return true;
7112     }
7113     faceNorm /= normSize;
7114
7115     // check if the point lays on face plane
7116     gp_Vec n2p( xyz[0], point );
7117     if ( fabs( n2p * faceNorm ) > tol )
7118       return true; // not on face plane
7119
7120     // check if point is out of face boundary:
7121     // define it by closest transition of a ray point->infinity through face boundary
7122     // on the face plane.
7123     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7124     // to find intersections of the ray with the boundary.
7125     gp_Vec ray = n2p;
7126     gp_Vec plnNorm = ray ^ faceNorm;
7127     normSize = plnNorm.Magnitude();
7128     if ( normSize <= tol ) return false; // point coincides with the first node
7129     plnNorm /= normSize;
7130     // for each node of the face, compute its signed distance to the plane
7131     vector<double> dist( nbNodes + 1);
7132     for ( i = 0; i < nbNodes; ++i )
7133     {
7134       gp_Vec n2p( xyz[i], point );
7135       dist[i] = n2p * plnNorm;
7136     }
7137     dist.back() = dist.front();
7138     // find the closest intersection
7139     int    iClosest = -1;
7140     double rClosest, distClosest = 1e100;;
7141     gp_Pnt pClosest;
7142     for ( i = 0; i < nbNodes; ++i )
7143     {
7144       double r;
7145       if ( fabs( dist[i]) < tol )
7146         r = 0.;
7147       else if ( fabs( dist[i+1]) < tol )
7148         r = 1.;
7149       else if ( dist[i] * dist[i+1] < 0 )
7150         r = dist[i] / ( dist[i] - dist[i+1] );
7151       else
7152         continue; // no intersection
7153       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7154       gp_Vec p2int ( point, pInt);
7155       if ( p2int * ray > -tol ) // right half-space
7156       {
7157         double intDist = p2int.SquareMagnitude();
7158         if ( intDist < distClosest )
7159         {
7160           iClosest = i;
7161           rClosest = r;
7162           pClosest = pInt;
7163           distClosest = intDist;
7164         }
7165       }
7166     }
7167     if ( iClosest < 0 )
7168       return true; // no intesections - out
7169
7170     // analyse transition
7171     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7172     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7173     gp_Vec p2int ( point, pClosest );
7174     bool out = (edgeNorm * p2int) < -tol;
7175     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7176       return out;
7177
7178     // ray pass through a face node; analyze transition through an adjacent edge
7179     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7180     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7181     gp_Vec edgeAdjacent( p1, p2 );
7182     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7183     bool out2 = (edgeNorm2 * p2int) < -tol;
7184
7185     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7186     return covexCorner ? (out || out2) : (out && out2);
7187   }
7188   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7189   {
7190     // point is out of edge if it is NOT ON any straight part of edge
7191     // (we consider quadratic edge as being composed of two straight parts)
7192     for ( i = 1; i < nbNodes; ++i )
7193     {
7194       gp_Vec edge( xyz[i-1], xyz[i]);
7195       gp_Vec n1p ( xyz[i-1], point);
7196       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7197       if ( dist > tol )
7198         continue;
7199       gp_Vec n2p( xyz[i], point );
7200       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7201         continue;
7202       return false; // point is ON this part
7203     }
7204     return true;
7205   }
7206   // Node or 0D element -------------------------------------------------------------------------
7207   {
7208     gp_Vec n2p ( xyz[0], point );
7209     return n2p.Magnitude() <= tol;
7210   }
7211   return true;
7212 }
7213
7214 //=======================================================================
7215 //function : SimplifyFace
7216 //purpose  :
7217 //=======================================================================
7218 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7219                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7220                                     vector<int>&                        quantities) const
7221 {
7222   int nbNodes = faceNodes.size();
7223
7224   if (nbNodes < 3)
7225     return 0;
7226
7227   set<const SMDS_MeshNode*> nodeSet;
7228
7229   // get simple seq of nodes
7230   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7231   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7232   int iSimple = 0, nbUnique = 0;
7233
7234   simpleNodes[iSimple++] = faceNodes[0];
7235   nbUnique++;
7236   for (int iCur = 1; iCur < nbNodes; iCur++) {
7237     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7238       simpleNodes[iSimple++] = faceNodes[iCur];
7239       if (nodeSet.insert( faceNodes[iCur] ).second)
7240         nbUnique++;
7241     }
7242   }
7243   int nbSimple = iSimple;
7244   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7245     nbSimple--;
7246     iSimple--;
7247   }
7248
7249   if (nbUnique < 3)
7250     return 0;
7251
7252   // separate loops
7253   int nbNew = 0;
7254   bool foundLoop = (nbSimple > nbUnique);
7255   while (foundLoop) {
7256     foundLoop = false;
7257     set<const SMDS_MeshNode*> loopSet;
7258     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7259       const SMDS_MeshNode* n = simpleNodes[iSimple];
7260       if (!loopSet.insert( n ).second) {
7261         foundLoop = true;
7262
7263         // separate loop
7264         int iC = 0, curLast = iSimple;
7265         for (; iC < curLast; iC++) {
7266           if (simpleNodes[iC] == n) break;
7267         }
7268         int loopLen = curLast - iC;
7269         if (loopLen > 2) {
7270           // create sub-element
7271           nbNew++;
7272           quantities.push_back(loopLen);
7273           for (; iC < curLast; iC++) {
7274             poly_nodes.push_back(simpleNodes[iC]);
7275           }
7276         }
7277         // shift the rest nodes (place from the first loop position)
7278         for (iC = curLast + 1; iC < nbSimple; iC++) {
7279           simpleNodes[iC - loopLen] = simpleNodes[iC];
7280         }
7281         nbSimple -= loopLen;
7282         iSimple -= loopLen;
7283       }
7284     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7285   } // while (foundLoop)
7286
7287   if (iSimple > 2) {
7288     nbNew++;
7289     quantities.push_back(iSimple);
7290     for (int i = 0; i < iSimple; i++)
7291       poly_nodes.push_back(simpleNodes[i]);
7292   }
7293
7294   return nbNew;
7295 }
7296
7297 //=======================================================================
7298 //function : MergeNodes
7299 //purpose  : In each group, the cdr of nodes are substituted by the first one
7300 //           in all elements.
7301 //=======================================================================
7302
7303 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7304 {
7305   MESSAGE("MergeNodes");
7306   myLastCreatedElems.Clear();
7307   myLastCreatedNodes.Clear();
7308
7309   SMESHDS_Mesh* aMesh = GetMeshDS();
7310
7311   TNodeNodeMap nodeNodeMap; // node to replace - new node
7312   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7313   list< int > rmElemIds, rmNodeIds;
7314
7315   // Fill nodeNodeMap and elems
7316
7317   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7318   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7319     list<const SMDS_MeshNode*>& nodes = *grIt;
7320     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7321     const SMDS_MeshNode* nToKeep = *nIt;
7322     //MESSAGE("node to keep " << nToKeep->GetID());
7323     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7324       const SMDS_MeshNode* nToRemove = *nIt;
7325       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7326       if ( nToRemove != nToKeep ) {
7327         //MESSAGE("  node to remove " << nToRemove->GetID());
7328         rmNodeIds.push_back( nToRemove->GetID() );
7329         AddToSameGroups( nToKeep, nToRemove, aMesh );
7330       }
7331
7332       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7333       while ( invElemIt->more() ) {
7334         const SMDS_MeshElement* elem = invElemIt->next();
7335         elems.insert(elem);
7336       }
7337     }
7338   }
7339   // Change element nodes or remove an element
7340
7341   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7342   for ( ; eIt != elems.end(); eIt++ ) {
7343     const SMDS_MeshElement* elem = *eIt;
7344     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7345     int nbNodes = elem->NbNodes();
7346     int aShapeId = FindShape( elem );
7347
7348     set<const SMDS_MeshNode*> nodeSet;
7349     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7350     int iUnique = 0, iCur = 0, nbRepl = 0;
7351     vector<int> iRepl( nbNodes );
7352
7353     // get new seq of nodes
7354     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7355     while ( itN->more() ) {
7356       const SMDS_MeshNode* n =
7357         static_cast<const SMDS_MeshNode*>( itN->next() );
7358
7359       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7360       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7361         n = (*nnIt).second;
7362         // BUG 0020185: begin
7363         {
7364           bool stopRecur = false;
7365           set<const SMDS_MeshNode*> nodesRecur;
7366           nodesRecur.insert(n);
7367           while (!stopRecur) {
7368             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7369             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7370               n = (*nnIt_i).second;
7371               if (!nodesRecur.insert(n).second) {
7372                 // error: recursive dependancy
7373                 stopRecur = true;
7374               }
7375             }
7376             else
7377               stopRecur = true;
7378           }
7379         }
7380         // BUG 0020185: end
7381         iRepl[ nbRepl++ ] = iCur;
7382       }
7383       curNodes[ iCur ] = n;
7384       bool isUnique = nodeSet.insert( n ).second;
7385       if ( isUnique ) {
7386         uniqueNodes[ iUnique++ ] = n;
7387         if ( nbRepl && iRepl[ nbRepl-1 ] == iCur )
7388           --nbRepl; // n do not stick to a node of the elem
7389       }
7390       iCur++;
7391     }
7392
7393     // Analyse element topology after replacement
7394
7395     bool isOk = true;
7396     int nbUniqueNodes = nodeSet.size();
7397     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7398     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7399       // Polygons and Polyhedral volumes
7400       if (elem->IsPoly()) {
7401
7402         if (elem->GetType() == SMDSAbs_Face) {
7403           // Polygon
7404           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7405           int inode = 0;
7406           for (; inode < nbNodes; inode++) {
7407             face_nodes[inode] = curNodes[inode];
7408           }
7409
7410           vector<const SMDS_MeshNode *> polygons_nodes;
7411           vector<int> quantities;
7412           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7413           if (nbNew > 0) {
7414             inode = 0;
7415             for (int iface = 0; iface < nbNew; iface++) {
7416               int nbNodes = quantities[iface];
7417               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7418               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7419                 poly_nodes[ii] = polygons_nodes[inode];
7420               }
7421               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7422               myLastCreatedElems.Append(newElem);
7423               if (aShapeId)
7424                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7425             }
7426
7427             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7428             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7429             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7430             int quid =0;
7431             if (nbNew > 0) quid = nbNew - 1;
7432             vector<int> newquant(quantities.begin()+quid, quantities.end());
7433             const SMDS_MeshElement* newElem = 0;
7434             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7435             myLastCreatedElems.Append(newElem);
7436             if ( aShapeId && newElem )
7437               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7438             rmElemIds.push_back(elem->GetID());
7439           }
7440           else {
7441             rmElemIds.push_back(elem->GetID());
7442           }
7443
7444         }
7445         else if (elem->GetType() == SMDSAbs_Volume) {
7446           // Polyhedral volume
7447           if (nbUniqueNodes < 4) {
7448             rmElemIds.push_back(elem->GetID());
7449           }
7450           else {
7451             // each face has to be analyzed in order to check volume validity
7452             const SMDS_VtkVolume* aPolyedre =
7453               dynamic_cast<const SMDS_VtkVolume*>( elem );
7454             if (aPolyedre) {
7455               int nbFaces = aPolyedre->NbFaces();
7456
7457               vector<const SMDS_MeshNode *> poly_nodes;
7458               vector<int> quantities;
7459
7460               for (int iface = 1; iface <= nbFaces; iface++) {
7461                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7462                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7463
7464                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7465                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7466                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7467                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7468                     faceNode = (*nnIt).second;
7469                   }
7470                   faceNodes[inode - 1] = faceNode;
7471                 }
7472
7473                 SimplifyFace(faceNodes, poly_nodes, quantities);
7474               }
7475
7476               if (quantities.size() > 3) {
7477                 // to be done: remove coincident faces
7478               }
7479
7480               if (quantities.size() > 3)
7481                 {
7482                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7483                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7484                   const SMDS_MeshElement* newElem = 0;
7485                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7486                   myLastCreatedElems.Append(newElem);
7487                   if ( aShapeId && newElem )
7488                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7489                   rmElemIds.push_back(elem->GetID());
7490                 }
7491             }
7492             else {
7493               rmElemIds.push_back(elem->GetID());
7494             }
7495           }
7496         }
7497         else {
7498         }
7499
7500         continue;
7501       } // poly element
7502
7503       // Regular elements
7504       // TODO not all the possible cases are solved. Find something more generic?
7505       switch ( nbNodes ) {
7506       case 2: ///////////////////////////////////// EDGE
7507         isOk = false; break;
7508       case 3: ///////////////////////////////////// TRIANGLE
7509         isOk = false; break;
7510       case 4:
7511         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7512           isOk = false;
7513         else { //////////////////////////////////// QUADRANGLE
7514           if ( nbUniqueNodes < 3 )
7515             isOk = false;
7516           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7517             isOk = false; // opposite nodes stick
7518           //MESSAGE("isOk " << isOk);
7519         }
7520         break;
7521       case 6: ///////////////////////////////////// PENTAHEDRON
7522         if ( nbUniqueNodes == 4 ) {
7523           // ---------------------------------> tetrahedron
7524           if (nbRepl == 3 &&
7525               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7526             // all top nodes stick: reverse a bottom
7527             uniqueNodes[ 0 ] = curNodes [ 1 ];
7528             uniqueNodes[ 1 ] = curNodes [ 0 ];
7529           }
7530           else if (nbRepl == 3 &&
7531                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7532             // all bottom nodes stick: set a top before
7533             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7534             uniqueNodes[ 0 ] = curNodes [ 3 ];
7535             uniqueNodes[ 1 ] = curNodes [ 4 ];
7536             uniqueNodes[ 2 ] = curNodes [ 5 ];
7537           }
7538           else if (nbRepl == 4 &&
7539                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7540             // a lateral face turns into a line: reverse a bottom
7541             uniqueNodes[ 0 ] = curNodes [ 1 ];
7542             uniqueNodes[ 1 ] = curNodes [ 0 ];
7543           }
7544           else
7545             isOk = false;
7546         }
7547         else if ( nbUniqueNodes == 5 ) {
7548           // PENTAHEDRON --------------------> 2 tetrahedrons
7549           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7550             // a bottom node sticks with a linked top one
7551             // 1.
7552             SMDS_MeshElement* newElem =
7553               aMesh->AddVolume(curNodes[ 3 ],
7554                                curNodes[ 4 ],
7555                                curNodes[ 5 ],
7556                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7557             myLastCreatedElems.Append(newElem);
7558             if ( aShapeId )
7559               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7560             // 2. : reverse a bottom
7561             uniqueNodes[ 0 ] = curNodes [ 1 ];
7562             uniqueNodes[ 1 ] = curNodes [ 0 ];
7563             nbUniqueNodes = 4;
7564           }
7565           else
7566             isOk = false;
7567         }
7568         else
7569           isOk = false;
7570         break;
7571       case 8: {
7572         if(elem->IsQuadratic()) { // Quadratic quadrangle
7573           //   1    5    2
7574           //    +---+---+
7575           //    |       |
7576           //    |       |
7577           //   4+       +6
7578           //    |       |
7579           //    |       |
7580           //    +---+---+
7581           //   0    7    3
7582           isOk = false;
7583           if(nbRepl==2) {
7584             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7585           }
7586           if(nbRepl==3) {
7587             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7588             nbUniqueNodes = 6;
7589             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7590               uniqueNodes[0] = curNodes[0];
7591               uniqueNodes[1] = curNodes[2];
7592               uniqueNodes[2] = curNodes[3];
7593               uniqueNodes[3] = curNodes[5];
7594               uniqueNodes[4] = curNodes[6];
7595               uniqueNodes[5] = curNodes[7];
7596               isOk = true;
7597             }
7598             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7599               uniqueNodes[0] = curNodes[0];
7600               uniqueNodes[1] = curNodes[1];
7601               uniqueNodes[2] = curNodes[2];
7602               uniqueNodes[3] = curNodes[4];
7603               uniqueNodes[4] = curNodes[5];
7604               uniqueNodes[5] = curNodes[6];
7605               isOk = true;
7606             }
7607             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7608               uniqueNodes[0] = curNodes[1];
7609               uniqueNodes[1] = curNodes[2];
7610               uniqueNodes[2] = curNodes[3];
7611               uniqueNodes[3] = curNodes[5];
7612               uniqueNodes[4] = curNodes[6];
7613               uniqueNodes[5] = curNodes[0];
7614               isOk = true;
7615             }
7616             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7617               uniqueNodes[0] = curNodes[0];
7618               uniqueNodes[1] = curNodes[1];
7619               uniqueNodes[2] = curNodes[3];
7620               uniqueNodes[3] = curNodes[4];
7621               uniqueNodes[4] = curNodes[6];
7622               uniqueNodes[5] = curNodes[7];
7623               isOk = true;
7624             }
7625             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7626               uniqueNodes[0] = curNodes[0];
7627               uniqueNodes[1] = curNodes[2];
7628               uniqueNodes[2] = curNodes[3];
7629               uniqueNodes[3] = curNodes[1];
7630               uniqueNodes[4] = curNodes[6];
7631               uniqueNodes[5] = curNodes[7];
7632               isOk = true;
7633             }
7634             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7635               uniqueNodes[0] = curNodes[0];
7636               uniqueNodes[1] = curNodes[1];
7637               uniqueNodes[2] = curNodes[2];
7638               uniqueNodes[3] = curNodes[4];
7639               uniqueNodes[4] = curNodes[5];
7640               uniqueNodes[5] = curNodes[7];
7641               isOk = true;
7642             }
7643             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7644               uniqueNodes[0] = curNodes[0];
7645               uniqueNodes[1] = curNodes[1];
7646               uniqueNodes[2] = curNodes[3];
7647               uniqueNodes[3] = curNodes[4];
7648               uniqueNodes[4] = curNodes[2];
7649               uniqueNodes[5] = curNodes[7];
7650               isOk = true;
7651             }
7652             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7653               uniqueNodes[0] = curNodes[0];
7654               uniqueNodes[1] = curNodes[1];
7655               uniqueNodes[2] = curNodes[2];
7656               uniqueNodes[3] = curNodes[4];
7657               uniqueNodes[4] = curNodes[5];
7658               uniqueNodes[5] = curNodes[3];
7659               isOk = true;
7660             }
7661           }
7662           if(nbRepl==4) {
7663             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7664           }
7665           if(nbRepl==5) {
7666             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7667           }
7668           break;
7669         }
7670         //////////////////////////////////// HEXAHEDRON
7671         isOk = false;
7672         SMDS_VolumeTool hexa (elem);
7673         hexa.SetExternalNormal();
7674         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7675           //////////////////////// HEX ---> 1 tetrahedron
7676           for ( int iFace = 0; iFace < 6; iFace++ ) {
7677             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7678             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7679                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7680                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7681               // one face turns into a point ...
7682               int iOppFace = hexa.GetOppFaceIndex( iFace );
7683               ind = hexa.GetFaceNodesIndices( iOppFace );
7684               int nbStick = 0;
7685               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7686                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7687                   nbStick++;
7688               }
7689               if ( nbStick == 1 ) {
7690                 // ... and the opposite one - into a triangle.
7691                 // set a top node
7692                 ind = hexa.GetFaceNodesIndices( iFace );
7693                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7694                 isOk = true;
7695               }
7696               break;
7697             }
7698           }
7699         }
7700         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7701           //////////////////////// HEX ---> 1 prism
7702           int nbTria = 0, iTria[3];
7703           const int *ind; // indices of face nodes
7704           // look for triangular faces
7705           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7706             ind = hexa.GetFaceNodesIndices( iFace );
7707             TIDSortedNodeSet faceNodes;
7708             for ( iCur = 0; iCur < 4; iCur++ )
7709               faceNodes.insert( curNodes[ind[iCur]] );
7710             if ( faceNodes.size() == 3 )
7711               iTria[ nbTria++ ] = iFace;
7712           }
7713           // check if triangles are opposite
7714           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7715           {
7716             isOk = true;
7717             // set nodes of the bottom triangle
7718             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7719             vector<int> indB;
7720             for ( iCur = 0; iCur < 4; iCur++ )
7721               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7722                 indB.push_back( ind[iCur] );
7723             if ( !hexa.IsForward() )
7724               std::swap( indB[0], indB[2] );
7725             for ( iCur = 0; iCur < 3; iCur++ )
7726               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7727             // set nodes of the top triangle
7728             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7729             for ( iCur = 0; iCur < 3; ++iCur )
7730               for ( int j = 0; j < 4; ++j )
7731                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7732                 {
7733                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7734                   break;
7735                 }
7736           }
7737           break;
7738         }
7739         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7740           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7741           for ( int iFace = 0; iFace < 6; iFace++ ) {
7742             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7743             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7744                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7745                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7746               // one face turns into a point ...
7747               int iOppFace = hexa.GetOppFaceIndex( iFace );
7748               ind = hexa.GetFaceNodesIndices( iOppFace );
7749               int nbStick = 0;
7750               iUnique = 2;  // reverse a tetrahedron 1 bottom
7751               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7752                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7753                   nbStick++;
7754                 else if ( iUnique >= 0 )
7755                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7756               }
7757               if ( nbStick == 0 ) {
7758                 // ... and the opposite one is a quadrangle
7759                 // set a top node
7760                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7761                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7762                 nbUniqueNodes = 4;
7763                 // tetrahedron 2
7764                 SMDS_MeshElement* newElem =
7765                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7766                                    curNodes[ind[ 3 ]],
7767                                    curNodes[ind[ 2 ]],
7768                                    curNodes[indTop[ 0 ]]);
7769                 myLastCreatedElems.Append(newElem);
7770                 if ( aShapeId )
7771                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7772                 isOk = true;
7773               }
7774               break;
7775             }
7776           }
7777         }
7778         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7779           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7780           // find indices of quad and tri faces
7781           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7782           for ( iFace = 0; iFace < 6; iFace++ ) {
7783             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7784             nodeSet.clear();
7785             for ( iCur = 0; iCur < 4; iCur++ )
7786               nodeSet.insert( curNodes[ind[ iCur ]] );
7787             nbUniqueNodes = nodeSet.size();
7788             if ( nbUniqueNodes == 3 )
7789               iTriFace[ nbTri++ ] = iFace;
7790             else if ( nbUniqueNodes == 4 )
7791               iQuadFace[ nbQuad++ ] = iFace;
7792           }
7793           if (nbQuad == 2 && nbTri == 4 &&
7794               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7795             // 2 opposite quadrangles stuck with a diagonal;
7796             // sample groups of merged indices: (0-4)(2-6)
7797             // --------------------------------------------> 2 tetrahedrons
7798             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7799             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7800             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7801             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7802                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7803               // stuck with 0-2 diagonal
7804               i0  = ind1[ 3 ];
7805               i1d = ind1[ 0 ];
7806               i2  = ind1[ 1 ];
7807               i3d = ind1[ 2 ];
7808               i0t = ind2[ 1 ];
7809               i2t = ind2[ 3 ];
7810             }
7811             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7812                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7813               // stuck with 1-3 diagonal
7814               i0  = ind1[ 0 ];
7815               i1d = ind1[ 1 ];
7816               i2  = ind1[ 2 ];
7817               i3d = ind1[ 3 ];
7818               i0t = ind2[ 0 ];
7819               i2t = ind2[ 1 ];
7820             }
7821             else {
7822               ASSERT(0);
7823             }
7824             // tetrahedron 1
7825             uniqueNodes[ 0 ] = curNodes [ i0 ];
7826             uniqueNodes[ 1 ] = curNodes [ i1d ];
7827             uniqueNodes[ 2 ] = curNodes [ i3d ];
7828             uniqueNodes[ 3 ] = curNodes [ i0t ];
7829             nbUniqueNodes = 4;
7830             // tetrahedron 2
7831             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7832                                                          curNodes[ i2 ],
7833                                                          curNodes[ i3d ],
7834                                                          curNodes[ i2t ]);
7835             myLastCreatedElems.Append(newElem);
7836             if ( aShapeId )
7837               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7838             isOk = true;
7839           }
7840           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7841                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7842             // --------------------------------------------> prism
7843             // find 2 opposite triangles
7844             nbUniqueNodes = 6;
7845             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7846               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7847                 // find indices of kept and replaced nodes
7848                 // and fill unique nodes of 2 opposite triangles
7849                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7850                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7851                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7852                 // fill unique nodes
7853                 iUnique = 0;
7854                 isOk = true;
7855                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7856                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7857                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7858                   if ( n == nInit ) {
7859                     // iCur of a linked node of the opposite face (make normals co-directed):
7860                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7861                     // check that correspondent corners of triangles are linked
7862                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7863                       isOk = false;
7864                     else {
7865                       uniqueNodes[ iUnique ] = n;
7866                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7867                       iUnique++;
7868                     }
7869                   }
7870                 }
7871                 break;
7872               }
7873             }
7874           }
7875         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7876         else
7877         {
7878           MESSAGE("MergeNodes() removes hexahedron "<< elem);
7879         }
7880         break;
7881       } // HEXAHEDRON
7882
7883       default:
7884         isOk = false;
7885       } // switch ( nbNodes )
7886
7887     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7888
7889     if ( isOk ) { // the elem remains valid after sticking nodes
7890       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
7891       {
7892         // Change nodes of polyedre
7893         const SMDS_VtkVolume* aPolyedre =
7894           dynamic_cast<const SMDS_VtkVolume*>( elem );
7895         if (aPolyedre) {
7896           int nbFaces = aPolyedre->NbFaces();
7897
7898           vector<const SMDS_MeshNode *> poly_nodes;
7899           vector<int> quantities (nbFaces);
7900
7901           for (int iface = 1; iface <= nbFaces; iface++) {
7902             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7903             quantities[iface - 1] = nbFaceNodes;
7904
7905             for (inode = 1; inode <= nbFaceNodes; inode++) {
7906               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7907
7908               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7909               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7910                 curNode = (*nnIt).second;
7911               }
7912               poly_nodes.push_back(curNode);
7913             }
7914           }
7915           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7916         }
7917       }
7918       else // replace non-polyhedron elements
7919       {
7920         const SMDSAbs_ElementType etyp = elem->GetType();
7921         const int elemId               = elem->GetID();
7922         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
7923         uniqueNodes.resize(nbUniqueNodes);
7924
7925         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
7926
7927         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7928         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
7929         if ( sm && newElem )
7930           sm->AddElement( newElem );
7931         if ( elem != newElem )
7932           ReplaceElemInGroups( elem, newElem, aMesh );
7933       }
7934     }
7935     else {
7936       // Remove invalid regular element or invalid polygon
7937       rmElemIds.push_back( elem->GetID() );
7938     }
7939
7940   } // loop on elements
7941
7942   // Remove bad elements, then equal nodes (order important)
7943
7944   Remove( rmElemIds, false );
7945   Remove( rmNodeIds, true );
7946
7947 }
7948
7949
7950 // ========================================================
7951 // class   : SortableElement
7952 // purpose : allow sorting elements basing on their nodes
7953 // ========================================================
7954 class SortableElement : public set <const SMDS_MeshElement*>
7955 {
7956 public:
7957
7958   SortableElement( const SMDS_MeshElement* theElem )
7959   {
7960     myElem = theElem;
7961     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7962     while ( nodeIt->more() )
7963       this->insert( nodeIt->next() );
7964   }
7965
7966   const SMDS_MeshElement* Get() const
7967   { return myElem; }
7968
7969   void Set(const SMDS_MeshElement* e) const
7970   { myElem = e; }
7971
7972
7973 private:
7974   mutable const SMDS_MeshElement* myElem;
7975 };
7976
7977 //=======================================================================
7978 //function : FindEqualElements
7979 //purpose  : Return list of group of elements built on the same nodes.
7980 //           Search among theElements or in the whole mesh if theElements is empty
7981 //=======================================================================
7982 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7983                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7984 {
7985   myLastCreatedElems.Clear();
7986   myLastCreatedNodes.Clear();
7987
7988   typedef set<const SMDS_MeshElement*> TElemsSet;
7989   typedef map< SortableElement, int > TMapOfNodeSet;
7990   typedef list<int> TGroupOfElems;
7991
7992   TElemsSet elems;
7993   if ( theElements.empty() )
7994   { // get all elements in the mesh
7995     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7996     while ( eIt->more() )
7997       elems.insert( elems.end(), eIt->next());
7998   }
7999   else
8000     elems = theElements;
8001
8002   vector< TGroupOfElems > arrayOfGroups;
8003   TGroupOfElems groupOfElems;
8004   TMapOfNodeSet mapOfNodeSet;
8005
8006   TElemsSet::iterator elemIt = elems.begin();
8007   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
8008     const SMDS_MeshElement* curElem = *elemIt;
8009     SortableElement SE(curElem);
8010     int ind = -1;
8011     // check uniqueness
8012     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
8013     if( !(pp.second) ) {
8014       TMapOfNodeSet::iterator& itSE = pp.first;
8015       ind = (*itSE).second;
8016       arrayOfGroups[ind].push_back(curElem->GetID());
8017     }
8018     else {
8019       groupOfElems.clear();
8020       groupOfElems.push_back(curElem->GetID());
8021       arrayOfGroups.push_back(groupOfElems);
8022       i++;
8023     }
8024   }
8025
8026   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
8027   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8028     groupOfElems = *groupIt;
8029     if ( groupOfElems.size() > 1 ) {
8030       groupOfElems.sort();
8031       theGroupsOfElementsID.push_back(groupOfElems);
8032     }
8033   }
8034 }
8035
8036 //=======================================================================
8037 //function : MergeElements
8038 //purpose  : In each given group, substitute all elements by the first one.
8039 //=======================================================================
8040
8041 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8042 {
8043   myLastCreatedElems.Clear();
8044   myLastCreatedNodes.Clear();
8045
8046   typedef list<int> TListOfIDs;
8047   TListOfIDs rmElemIds; // IDs of elems to remove
8048
8049   SMESHDS_Mesh* aMesh = GetMeshDS();
8050
8051   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8052   while ( groupsIt != theGroupsOfElementsID.end() ) {
8053     TListOfIDs& aGroupOfElemID = *groupsIt;
8054     aGroupOfElemID.sort();
8055     int elemIDToKeep = aGroupOfElemID.front();
8056     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8057     aGroupOfElemID.pop_front();
8058     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8059     while ( idIt != aGroupOfElemID.end() ) {
8060       int elemIDToRemove = *idIt;
8061       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8062       // add the kept element in groups of removed one (PAL15188)
8063       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8064       rmElemIds.push_back( elemIDToRemove );
8065       ++idIt;
8066     }
8067     ++groupsIt;
8068   }
8069
8070   Remove( rmElemIds, false );
8071 }
8072
8073 //=======================================================================
8074 //function : MergeEqualElements
8075 //purpose  : Remove all but one of elements built on the same nodes.
8076 //=======================================================================
8077
8078 void SMESH_MeshEditor::MergeEqualElements()
8079 {
8080   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8081                                                  to merge equal elements in the whole mesh */
8082   TListOfListOfElementsID aGroupsOfElementsID;
8083   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8084   MergeElements(aGroupsOfElementsID);
8085 }
8086
8087 //=======================================================================
8088 //function : FindFaceInSet
8089 //purpose  : Return a face having linked nodes n1 and n2 and which is
8090 //           - not in avoidSet,
8091 //           - in elemSet provided that !elemSet.empty()
8092 //           i1 and i2 optionally returns indices of n1 and n2
8093 //=======================================================================
8094
8095 const SMDS_MeshElement*
8096 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8097                                 const SMDS_MeshNode*    n2,
8098                                 const TIDSortedElemSet& elemSet,
8099                                 const TIDSortedElemSet& avoidSet,
8100                                 int*                    n1ind,
8101                                 int*                    n2ind)
8102
8103 {
8104   int i1, i2;
8105   const SMDS_MeshElement* face = 0;
8106
8107   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8108   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8109   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8110   {
8111     //MESSAGE("in while ( invElemIt->more() && !face )");
8112     const SMDS_MeshElement* elem = invElemIt->next();
8113     if (avoidSet.count( elem ))
8114       continue;
8115     if ( !elemSet.empty() && !elemSet.count( elem ))
8116       continue;
8117     // index of n1
8118     i1 = elem->GetNodeIndex( n1 );
8119     // find a n2 linked to n1
8120     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8121     for ( int di = -1; di < 2 && !face; di += 2 )
8122     {
8123       i2 = (i1+di+nbN) % nbN;
8124       if ( elem->GetNode( i2 ) == n2 )
8125         face = elem;
8126     }
8127     if ( !face && elem->IsQuadratic())
8128     {
8129       // analysis for quadratic elements using all nodes
8130       const SMDS_VtkFace* F =
8131         dynamic_cast<const SMDS_VtkFace*>(elem);
8132       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8133       // use special nodes iterator
8134       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8135       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8136       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8137       {
8138         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8139         if ( n1 == prevN && n2 == n )
8140         {
8141           face = elem;
8142         }
8143         else if ( n2 == prevN && n1 == n )
8144         {
8145           face = elem; swap( i1, i2 );
8146         }
8147         prevN = n;
8148       }
8149     }
8150   }
8151   if ( n1ind ) *n1ind = i1;
8152   if ( n2ind ) *n2ind = i2;
8153   return face;
8154 }
8155
8156 //=======================================================================
8157 //function : findAdjacentFace
8158 //purpose  :
8159 //=======================================================================
8160
8161 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8162                                                 const SMDS_MeshNode* n2,
8163                                                 const SMDS_MeshElement* elem)
8164 {
8165   TIDSortedElemSet elemSet, avoidSet;
8166   if ( elem )
8167     avoidSet.insert ( elem );
8168   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8169 }
8170
8171 //=======================================================================
8172 //function : FindFreeBorder
8173 //purpose  :
8174 //=======================================================================
8175
8176 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8177
8178 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8179                                        const SMDS_MeshNode*             theSecondNode,
8180                                        const SMDS_MeshNode*             theLastNode,
8181                                        list< const SMDS_MeshNode* > &   theNodes,
8182                                        list< const SMDS_MeshElement* >& theFaces)
8183 {
8184   if ( !theFirstNode || !theSecondNode )
8185     return false;
8186   // find border face between theFirstNode and theSecondNode
8187   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8188   if ( !curElem )
8189     return false;
8190
8191   theFaces.push_back( curElem );
8192   theNodes.push_back( theFirstNode );
8193   theNodes.push_back( theSecondNode );
8194
8195   //vector<const SMDS_MeshNode*> nodes;
8196   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8197   TIDSortedElemSet foundElems;
8198   bool needTheLast = ( theLastNode != 0 );
8199
8200   while ( nStart != theLastNode ) {
8201     if ( nStart == theFirstNode )
8202       return !needTheLast;
8203
8204     // find all free border faces sharing form nStart
8205
8206     list< const SMDS_MeshElement* > curElemList;
8207     list< const SMDS_MeshNode* > nStartList;
8208     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8209     while ( invElemIt->more() ) {
8210       const SMDS_MeshElement* e = invElemIt->next();
8211       if ( e == curElem || foundElems.insert( e ).second ) {
8212         // get nodes
8213         int iNode = 0, nbNodes = e->NbNodes();
8214         //const SMDS_MeshNode* nodes[nbNodes+1];
8215         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8216
8217         if(e->IsQuadratic()) {
8218           const SMDS_VtkFace* F =
8219             dynamic_cast<const SMDS_VtkFace*>(e);
8220           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8221           // use special nodes iterator
8222           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8223           while( anIter->more() ) {
8224             nodes[ iNode++ ] = cast2Node(anIter->next());
8225           }
8226         }
8227         else {
8228           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8229           while ( nIt->more() )
8230             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8231         }
8232         nodes[ iNode ] = nodes[ 0 ];
8233         // check 2 links
8234         for ( iNode = 0; iNode < nbNodes; iNode++ )
8235           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8236                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8237               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8238           {
8239             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8240             curElemList.push_back( e );
8241           }
8242       }
8243     }
8244     // analyse the found
8245
8246     int nbNewBorders = curElemList.size();
8247     if ( nbNewBorders == 0 ) {
8248       // no free border furthermore
8249       return !needTheLast;
8250     }
8251     else if ( nbNewBorders == 1 ) {
8252       // one more element found
8253       nIgnore = nStart;
8254       nStart = nStartList.front();
8255       curElem = curElemList.front();
8256       theFaces.push_back( curElem );
8257       theNodes.push_back( nStart );
8258     }
8259     else {
8260       // several continuations found
8261       list< const SMDS_MeshElement* >::iterator curElemIt;
8262       list< const SMDS_MeshNode* >::iterator nStartIt;
8263       // check if one of them reached the last node
8264       if ( needTheLast ) {
8265         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8266              curElemIt!= curElemList.end();
8267              curElemIt++, nStartIt++ )
8268           if ( *nStartIt == theLastNode ) {
8269             theFaces.push_back( *curElemIt );
8270             theNodes.push_back( *nStartIt );
8271             return true;
8272           }
8273       }
8274       // find the best free border by the continuations
8275       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8276       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8277       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8278            curElemIt!= curElemList.end();
8279            curElemIt++, nStartIt++ )
8280       {
8281         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8282         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8283         // find one more free border
8284         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8285           cNL->clear();
8286           cFL->clear();
8287         }
8288         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8289           // choice: clear a worse one
8290           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8291           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8292           contNodes[ iWorse ].clear();
8293           contFaces[ iWorse ].clear();
8294         }
8295       }
8296       if ( contNodes[0].empty() && contNodes[1].empty() )
8297         return false;
8298
8299       // append the best free border
8300       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8301       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8302       theNodes.pop_back(); // remove nIgnore
8303       theNodes.pop_back(); // remove nStart
8304       theFaces.pop_back(); // remove curElem
8305       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8306       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8307       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8308       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8309       return true;
8310
8311     } // several continuations found
8312   } // while ( nStart != theLastNode )
8313
8314   return true;
8315 }
8316
8317 //=======================================================================
8318 //function : CheckFreeBorderNodes
8319 //purpose  : Return true if the tree nodes are on a free border
8320 //=======================================================================
8321
8322 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8323                                             const SMDS_MeshNode* theNode2,
8324                                             const SMDS_MeshNode* theNode3)
8325 {
8326   list< const SMDS_MeshNode* > nodes;
8327   list< const SMDS_MeshElement* > faces;
8328   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8329 }
8330
8331 //=======================================================================
8332 //function : SewFreeBorder
8333 //purpose  :
8334 //=======================================================================
8335
8336 SMESH_MeshEditor::Sew_Error
8337 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8338                                  const SMDS_MeshNode* theBordSecondNode,
8339                                  const SMDS_MeshNode* theBordLastNode,
8340                                  const SMDS_MeshNode* theSideFirstNode,
8341                                  const SMDS_MeshNode* theSideSecondNode,
8342                                  const SMDS_MeshNode* theSideThirdNode,
8343                                  const bool           theSideIsFreeBorder,
8344                                  const bool           toCreatePolygons,
8345                                  const bool           toCreatePolyedrs)
8346 {
8347   myLastCreatedElems.Clear();
8348   myLastCreatedNodes.Clear();
8349
8350   MESSAGE("::SewFreeBorder()");
8351   Sew_Error aResult = SEW_OK;
8352
8353   // ====================================
8354   //    find side nodes and elements
8355   // ====================================
8356
8357   list< const SMDS_MeshNode* > nSide[ 2 ];
8358   list< const SMDS_MeshElement* > eSide[ 2 ];
8359   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8360   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8361
8362   // Free border 1
8363   // --------------
8364   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8365                       nSide[0], eSide[0])) {
8366     MESSAGE(" Free Border 1 not found " );
8367     aResult = SEW_BORDER1_NOT_FOUND;
8368   }
8369   if (theSideIsFreeBorder) {
8370     // Free border 2
8371     // --------------
8372     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8373                         nSide[1], eSide[1])) {
8374       MESSAGE(" Free Border 2 not found " );
8375       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8376     }
8377   }
8378   if ( aResult != SEW_OK )
8379     return aResult;
8380
8381   if (!theSideIsFreeBorder) {
8382     // Side 2
8383     // --------------
8384
8385     // -------------------------------------------------------------------------
8386     // Algo:
8387     // 1. If nodes to merge are not coincident, move nodes of the free border
8388     //    from the coord sys defined by the direction from the first to last
8389     //    nodes of the border to the correspondent sys of the side 2
8390     // 2. On the side 2, find the links most co-directed with the correspondent
8391     //    links of the free border
8392     // -------------------------------------------------------------------------
8393
8394     // 1. Since sewing may break if there are volumes to split on the side 2,
8395     //    we wont move nodes but just compute new coordinates for them
8396     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8397     TNodeXYZMap nBordXYZ;
8398     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8399     list< const SMDS_MeshNode* >::iterator nBordIt;
8400
8401     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8402     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8403     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8404     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8405     double tol2 = 1.e-8;
8406     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8407     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8408       // Need node movement.
8409
8410       // find X and Z axes to create trsf
8411       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8412       gp_Vec X = Zs ^ Zb;
8413       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8414         // Zb || Zs
8415         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8416
8417       // coord systems
8418       gp_Ax3 toBordAx( Pb1, Zb, X );
8419       gp_Ax3 fromSideAx( Ps1, Zs, X );
8420       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8421       // set trsf
8422       gp_Trsf toBordSys, fromSide2Sys;
8423       toBordSys.SetTransformation( toBordAx );
8424       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8425       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8426
8427       // move
8428       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8429         const SMDS_MeshNode* n = *nBordIt;
8430         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8431         toBordSys.Transforms( xyz );
8432         fromSide2Sys.Transforms( xyz );
8433         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8434       }
8435     }
8436     else {
8437       // just insert nodes XYZ in the nBordXYZ map
8438       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8439         const SMDS_MeshNode* n = *nBordIt;
8440         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8441       }
8442     }
8443
8444     // 2. On the side 2, find the links most co-directed with the correspondent
8445     //    links of the free border
8446
8447     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8448     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8449     sideNodes.push_back( theSideFirstNode );
8450
8451     bool hasVolumes = false;
8452     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8453     set<long> foundSideLinkIDs, checkedLinkIDs;
8454     SMDS_VolumeTool volume;
8455     //const SMDS_MeshNode* faceNodes[ 4 ];
8456
8457     const SMDS_MeshNode*    sideNode;
8458     const SMDS_MeshElement* sideElem;
8459     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8460     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8461     nBordIt = bordNodes.begin();
8462     nBordIt++;
8463     // border node position and border link direction to compare with
8464     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8465     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8466     // choose next side node by link direction or by closeness to
8467     // the current border node:
8468     bool searchByDir = ( *nBordIt != theBordLastNode );
8469     do {
8470       // find the next node on the Side 2
8471       sideNode = 0;
8472       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8473       long linkID;
8474       checkedLinkIDs.clear();
8475       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8476
8477       // loop on inverse elements of current node (prevSideNode) on the Side 2
8478       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8479       while ( invElemIt->more() )
8480       {
8481         const SMDS_MeshElement* elem = invElemIt->next();
8482         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8483         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8484         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8485         bool isVolume = volume.Set( elem );
8486         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8487         if ( isVolume ) // --volume
8488           hasVolumes = true;
8489         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8490           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8491           if(elem->IsQuadratic()) {
8492             const SMDS_VtkFace* F =
8493               dynamic_cast<const SMDS_VtkFace*>(elem);
8494             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8495             // use special nodes iterator
8496             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8497             while( anIter->more() ) {
8498               nodes[ iNode ] = cast2Node(anIter->next());
8499               if ( nodes[ iNode++ ] == prevSideNode )
8500                 iPrevNode = iNode - 1;
8501             }
8502           }
8503           else {
8504             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8505             while ( nIt->more() ) {
8506               nodes[ iNode ] = cast2Node( nIt->next() );
8507               if ( nodes[ iNode++ ] == prevSideNode )
8508                 iPrevNode = iNode - 1;
8509             }
8510           }
8511           // there are 2 links to check
8512           nbNodes = 2;
8513         }
8514         else // --edge
8515           continue;
8516         // loop on links, to be precise, on the second node of links
8517         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8518           const SMDS_MeshNode* n = nodes[ iNode ];
8519           if ( isVolume ) {
8520             if ( !volume.IsLinked( n, prevSideNode ))
8521               continue;
8522           }
8523           else {
8524             if ( iNode ) // a node before prevSideNode
8525               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8526             else         // a node after prevSideNode
8527               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8528           }
8529           // check if this link was already used
8530           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8531           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8532           if (!isJustChecked &&
8533               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8534           {
8535             // test a link geometrically
8536             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8537             bool linkIsBetter = false;
8538             double dot = 0.0, dist = 0.0;
8539             if ( searchByDir ) { // choose most co-directed link
8540               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8541               linkIsBetter = ( dot > maxDot );
8542             }
8543             else { // choose link with the node closest to bordPos
8544               dist = ( nextXYZ - bordPos ).SquareModulus();
8545               linkIsBetter = ( dist < minDist );
8546             }
8547             if ( linkIsBetter ) {
8548               maxDot = dot;
8549               minDist = dist;
8550               linkID = iLink;
8551               sideNode = n;
8552               sideElem = elem;
8553             }
8554           }
8555         }
8556       } // loop on inverse elements of prevSideNode
8557
8558       if ( !sideNode ) {
8559         MESSAGE(" Cant find path by links of the Side 2 ");
8560         return SEW_BAD_SIDE_NODES;
8561       }
8562       sideNodes.push_back( sideNode );
8563       sideElems.push_back( sideElem );
8564       foundSideLinkIDs.insert ( linkID );
8565       prevSideNode = sideNode;
8566
8567       if ( *nBordIt == theBordLastNode )
8568         searchByDir = false;
8569       else {
8570         // find the next border link to compare with
8571         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8572         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8573         // move to next border node if sideNode is before forward border node (bordPos)
8574         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8575           prevBordNode = *nBordIt;
8576           nBordIt++;
8577           bordPos = nBordXYZ[ *nBordIt ];
8578           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8579           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8580         }
8581       }
8582     }
8583     while ( sideNode != theSideSecondNode );
8584
8585     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8586       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8587       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8588     }
8589   } // end nodes search on the side 2
8590
8591   // ============================
8592   // sew the border to the side 2
8593   // ============================
8594
8595   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8596   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8597
8598   TListOfListOfNodes nodeGroupsToMerge;
8599   if ( nbNodes[0] == nbNodes[1] ||
8600        ( theSideIsFreeBorder && !theSideThirdNode)) {
8601
8602     // all nodes are to be merged
8603
8604     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8605          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8606          nIt[0]++, nIt[1]++ )
8607     {
8608       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8609       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8610       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8611     }
8612   }
8613   else {
8614
8615     // insert new nodes into the border and the side to get equal nb of segments
8616
8617     // get normalized parameters of nodes on the borders
8618     //double param[ 2 ][ maxNbNodes ];
8619     double* param[ 2 ];
8620     param[0] = new double [ maxNbNodes ];
8621     param[1] = new double [ maxNbNodes ];
8622     int iNode, iBord;
8623     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8624       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8625       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8626       const SMDS_MeshNode* nPrev = *nIt;
8627       double bordLength = 0;
8628       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8629         const SMDS_MeshNode* nCur = *nIt;
8630         gp_XYZ segment (nCur->X() - nPrev->X(),
8631                         nCur->Y() - nPrev->Y(),
8632                         nCur->Z() - nPrev->Z());
8633         double segmentLen = segment.Modulus();
8634         bordLength += segmentLen;
8635         param[ iBord ][ iNode ] = bordLength;
8636         nPrev = nCur;
8637       }
8638       // normalize within [0,1]
8639       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8640         param[ iBord ][ iNode ] /= bordLength;
8641       }
8642     }
8643
8644     // loop on border segments
8645     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8646     int i[ 2 ] = { 0, 0 };
8647     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8648     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8649
8650     TElemOfNodeListMap insertMap;
8651     TElemOfNodeListMap::iterator insertMapIt;
8652     // insertMap is
8653     // key:   elem to insert nodes into
8654     // value: 2 nodes to insert between + nodes to be inserted
8655     do {
8656       bool next[ 2 ] = { false, false };
8657
8658       // find min adjacent segment length after sewing
8659       double nextParam = 10., prevParam = 0;
8660       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8661         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8662           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8663         if ( i[ iBord ] > 0 )
8664           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8665       }
8666       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8667       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8668       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8669
8670       // choose to insert or to merge nodes
8671       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8672       if ( Abs( du ) <= minSegLen * 0.2 ) {
8673         // merge
8674         // ------
8675         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8676         const SMDS_MeshNode* n0 = *nIt[0];
8677         const SMDS_MeshNode* n1 = *nIt[1];
8678         nodeGroupsToMerge.back().push_back( n1 );
8679         nodeGroupsToMerge.back().push_back( n0 );
8680         // position of node of the border changes due to merge
8681         param[ 0 ][ i[0] ] += du;
8682         // move n1 for the sake of elem shape evaluation during insertion.
8683         // n1 will be removed by MergeNodes() anyway
8684         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8685         next[0] = next[1] = true;
8686       }
8687       else {
8688         // insert
8689         // ------
8690         int intoBord = ( du < 0 ) ? 0 : 1;
8691         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8692         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8693         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8694         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8695         if ( intoBord == 1 ) {
8696           // move node of the border to be on a link of elem of the side
8697           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8698           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8699           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8700           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8701           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8702         }
8703         insertMapIt = insertMap.find( elem );
8704         bool notFound = ( insertMapIt == insertMap.end() );
8705         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8706         if ( otherLink ) {
8707           // insert into another link of the same element:
8708           // 1. perform insertion into the other link of the elem
8709           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8710           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8711           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8712           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8713           // 2. perform insertion into the link of adjacent faces
8714           while (true) {
8715             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8716             if ( adjElem )
8717               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8718             else
8719               break;
8720           }
8721           if (toCreatePolyedrs) {
8722             // perform insertion into the links of adjacent volumes
8723             UpdateVolumes(n12, n22, nodeList);
8724           }
8725           // 3. find an element appeared on n1 and n2 after the insertion
8726           insertMap.erase( elem );
8727           elem = findAdjacentFace( n1, n2, 0 );
8728         }
8729         if ( notFound || otherLink ) {
8730           // add element and nodes of the side into the insertMap
8731           insertMapIt = insertMap.insert
8732             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8733           (*insertMapIt).second.push_back( n1 );
8734           (*insertMapIt).second.push_back( n2 );
8735         }
8736         // add node to be inserted into elem
8737         (*insertMapIt).second.push_back( nIns );
8738         next[ 1 - intoBord ] = true;
8739       }
8740
8741       // go to the next segment
8742       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8743         if ( next[ iBord ] ) {
8744           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8745             eIt[ iBord ]++;
8746           nPrev[ iBord ] = *nIt[ iBord ];
8747           nIt[ iBord ]++; i[ iBord ]++;
8748         }
8749       }
8750     }
8751     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8752
8753     // perform insertion of nodes into elements
8754
8755     for (insertMapIt = insertMap.begin();
8756          insertMapIt != insertMap.end();
8757          insertMapIt++ )
8758     {
8759       const SMDS_MeshElement* elem = (*insertMapIt).first;
8760       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8761       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8762       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8763
8764       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8765
8766       if ( !theSideIsFreeBorder ) {
8767         // look for and insert nodes into the faces adjacent to elem
8768         while (true) {
8769           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8770           if ( adjElem )
8771             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8772           else
8773             break;
8774         }
8775       }
8776       if (toCreatePolyedrs) {
8777         // perform insertion into the links of adjacent volumes
8778         UpdateVolumes(n1, n2, nodeList);
8779       }
8780     }
8781
8782     delete param[0];
8783     delete param[1];
8784   } // end: insert new nodes
8785
8786   MergeNodes ( nodeGroupsToMerge );
8787
8788   return aResult;
8789 }
8790
8791 //=======================================================================
8792 //function : InsertNodesIntoLink
8793 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8794 //           and theBetweenNode2 and split theElement
8795 //=======================================================================
8796
8797 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8798                                            const SMDS_MeshNode*        theBetweenNode1,
8799                                            const SMDS_MeshNode*        theBetweenNode2,
8800                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8801                                            const bool                  toCreatePoly)
8802 {
8803   if ( theFace->GetType() != SMDSAbs_Face ) return;
8804
8805   // find indices of 2 link nodes and of the rest nodes
8806   int iNode = 0, il1, il2, i3, i4;
8807   il1 = il2 = i3 = i4 = -1;
8808   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8809   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8810
8811   if(theFace->IsQuadratic()) {
8812     const SMDS_VtkFace* F =
8813       dynamic_cast<const SMDS_VtkFace*>(theFace);
8814     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8815     // use special nodes iterator
8816     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8817     while( anIter->more() ) {
8818       const SMDS_MeshNode* n = cast2Node(anIter->next());
8819       if ( n == theBetweenNode1 )
8820         il1 = iNode;
8821       else if ( n == theBetweenNode2 )
8822         il2 = iNode;
8823       else if ( i3 < 0 )
8824         i3 = iNode;
8825       else
8826         i4 = iNode;
8827       nodes[ iNode++ ] = n;
8828     }
8829   }
8830   else {
8831     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8832     while ( nodeIt->more() ) {
8833       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8834       if ( n == theBetweenNode1 )
8835         il1 = iNode;
8836       else if ( n == theBetweenNode2 )
8837         il2 = iNode;
8838       else if ( i3 < 0 )
8839         i3 = iNode;
8840       else
8841         i4 = iNode;
8842       nodes[ iNode++ ] = n;
8843     }
8844   }
8845   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8846     return ;
8847
8848   // arrange link nodes to go one after another regarding the face orientation
8849   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8850   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8851   if ( reverse ) {
8852     iNode = il1;
8853     il1 = il2;
8854     il2 = iNode;
8855     aNodesToInsert.reverse();
8856   }
8857   // check that not link nodes of a quadrangles are in good order
8858   int nbFaceNodes = theFace->NbNodes();
8859   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8860     iNode = i3;
8861     i3 = i4;
8862     i4 = iNode;
8863   }
8864
8865   if (toCreatePoly || theFace->IsPoly()) {
8866
8867     iNode = 0;
8868     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8869
8870     // add nodes of face up to first node of link
8871     bool isFLN = false;
8872
8873     if(theFace->IsQuadratic()) {
8874       const SMDS_VtkFace* F =
8875         dynamic_cast<const SMDS_VtkFace*>(theFace);
8876       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8877       // use special nodes iterator
8878       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8879       while( anIter->more()  && !isFLN ) {
8880         const SMDS_MeshNode* n = cast2Node(anIter->next());
8881         poly_nodes[iNode++] = n;
8882         if (n == nodes[il1]) {
8883           isFLN = true;
8884         }
8885       }
8886       // add nodes to insert
8887       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8888       for (; nIt != aNodesToInsert.end(); nIt++) {
8889         poly_nodes[iNode++] = *nIt;
8890       }
8891       // add nodes of face starting from last node of link
8892       while ( anIter->more() ) {
8893         poly_nodes[iNode++] = cast2Node(anIter->next());
8894       }
8895     }
8896     else {
8897       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8898       while ( nodeIt->more() && !isFLN ) {
8899         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8900         poly_nodes[iNode++] = n;
8901         if (n == nodes[il1]) {
8902           isFLN = true;
8903         }
8904       }
8905       // add nodes to insert
8906       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8907       for (; nIt != aNodesToInsert.end(); nIt++) {
8908         poly_nodes[iNode++] = *nIt;
8909       }
8910       // add nodes of face starting from last node of link
8911       while ( nodeIt->more() ) {
8912         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8913         poly_nodes[iNode++] = n;
8914       }
8915     }
8916
8917     // edit or replace the face
8918     SMESHDS_Mesh *aMesh = GetMeshDS();
8919
8920     if (theFace->IsPoly()) {
8921       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8922     }
8923     else {
8924       int aShapeId = FindShape( theFace );
8925
8926       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8927       myLastCreatedElems.Append(newElem);
8928       if ( aShapeId && newElem )
8929         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8930
8931       aMesh->RemoveElement(theFace);
8932     }
8933     return;
8934   }
8935
8936   SMESHDS_Mesh *aMesh = GetMeshDS();
8937   if( !theFace->IsQuadratic() ) {
8938
8939     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8940     int nbLinkNodes = 2 + aNodesToInsert.size();
8941     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8942     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8943     linkNodes[ 0 ] = nodes[ il1 ];
8944     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8945     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8946     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8947       linkNodes[ iNode++ ] = *nIt;
8948     }
8949     // decide how to split a quadrangle: compare possible variants
8950     // and choose which of splits to be a quadrangle
8951     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8952     if ( nbFaceNodes == 3 ) {
8953       iBestQuad = nbSplits;
8954       i4 = i3;
8955     }
8956     else if ( nbFaceNodes == 4 ) {
8957       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8958       double aBestRate = DBL_MAX;
8959       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8960         i1 = 0; i2 = 1;
8961         double aBadRate = 0;
8962         // evaluate elements quality
8963         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8964           if ( iSplit == iQuad ) {
8965             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8966                                    linkNodes[ i2++ ],
8967                                    nodes[ i3 ],
8968                                    nodes[ i4 ]);
8969             aBadRate += getBadRate( &quad, aCrit );
8970           }
8971           else {
8972             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8973                                    linkNodes[ i2++ ],
8974                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8975             aBadRate += getBadRate( &tria, aCrit );
8976           }
8977         }
8978         // choice
8979         if ( aBadRate < aBestRate ) {
8980           iBestQuad = iQuad;
8981           aBestRate = aBadRate;
8982         }
8983       }
8984     }
8985
8986     // create new elements
8987     int aShapeId = FindShape( theFace );
8988
8989     i1 = 0; i2 = 1;
8990     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8991       SMDS_MeshElement* newElem = 0;
8992       if ( iSplit == iBestQuad )
8993         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8994                                   linkNodes[ i2++ ],
8995                                   nodes[ i3 ],
8996                                   nodes[ i4 ]);
8997       else
8998         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8999                                   linkNodes[ i2++ ],
9000                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
9001       myLastCreatedElems.Append(newElem);
9002       if ( aShapeId && newElem )
9003         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9004     }
9005
9006     // change nodes of theFace
9007     const SMDS_MeshNode* newNodes[ 4 ];
9008     newNodes[ 0 ] = linkNodes[ i1 ];
9009     newNodes[ 1 ] = linkNodes[ i2 ];
9010     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
9011     newNodes[ 3 ] = nodes[ i4 ];
9012     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
9013     const SMDS_MeshElement* newElem = 0;
9014     if (iSplit == iBestQuad)
9015       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
9016     else
9017       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
9018     myLastCreatedElems.Append(newElem);
9019     if ( aShapeId && newElem )
9020       aMesh->SetMeshElementOnShape( newElem, aShapeId );
9021 } // end if(!theFace->IsQuadratic())
9022   else { // theFace is quadratic
9023     // we have to split theFace on simple triangles and one simple quadrangle
9024     int tmp = il1/2;
9025     int nbshift = tmp*2;
9026     // shift nodes in nodes[] by nbshift
9027     int i,j;
9028     for(i=0; i<nbshift; i++) {
9029       const SMDS_MeshNode* n = nodes[0];
9030       for(j=0; j<nbFaceNodes-1; j++) {
9031         nodes[j] = nodes[j+1];
9032       }
9033       nodes[nbFaceNodes-1] = n;
9034     }
9035     il1 = il1 - nbshift;
9036     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9037     //   n0      n1     n2    n0      n1     n2
9038     //     +-----+-----+        +-----+-----+
9039     //      \         /         |           |
9040     //       \       /          |           |
9041     //      n5+     +n3       n7+           +n3
9042     //         \   /            |           |
9043     //          \ /             |           |
9044     //           +              +-----+-----+
9045     //           n4           n6      n5     n4
9046
9047     // create new elements
9048     int aShapeId = FindShape( theFace );
9049
9050     int n1,n2,n3;
9051     if(nbFaceNodes==6) { // quadratic triangle
9052       SMDS_MeshElement* newElem =
9053         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9054       myLastCreatedElems.Append(newElem);
9055       if ( aShapeId && newElem )
9056         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9057       if(theFace->IsMediumNode(nodes[il1])) {
9058         // create quadrangle
9059         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9060         myLastCreatedElems.Append(newElem);
9061         if ( aShapeId && newElem )
9062           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9063         n1 = 1;
9064         n2 = 2;
9065         n3 = 3;
9066       }
9067       else {
9068         // create quadrangle
9069         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9070         myLastCreatedElems.Append(newElem);
9071         if ( aShapeId && newElem )
9072           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9073         n1 = 0;
9074         n2 = 1;
9075         n3 = 5;
9076       }
9077     }
9078     else { // nbFaceNodes==8 - quadratic quadrangle
9079       SMDS_MeshElement* newElem =
9080         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9081       myLastCreatedElems.Append(newElem);
9082       if ( aShapeId && newElem )
9083         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9084       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9085       myLastCreatedElems.Append(newElem);
9086       if ( aShapeId && newElem )
9087         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9088       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9089       myLastCreatedElems.Append(newElem);
9090       if ( aShapeId && newElem )
9091         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9092       if(theFace->IsMediumNode(nodes[il1])) {
9093         // create quadrangle
9094         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9095         myLastCreatedElems.Append(newElem);
9096         if ( aShapeId && newElem )
9097           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9098         n1 = 1;
9099         n2 = 2;
9100         n3 = 3;
9101       }
9102       else {
9103         // create quadrangle
9104         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9105         myLastCreatedElems.Append(newElem);
9106         if ( aShapeId && newElem )
9107           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9108         n1 = 0;
9109         n2 = 1;
9110         n3 = 7;
9111       }
9112     }
9113     // create needed triangles using n1,n2,n3 and inserted nodes
9114     int nbn = 2 + aNodesToInsert.size();
9115     //const SMDS_MeshNode* aNodes[nbn];
9116     vector<const SMDS_MeshNode*> aNodes(nbn);
9117     aNodes[0] = nodes[n1];
9118     aNodes[nbn-1] = nodes[n2];
9119     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9120     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9121       aNodes[iNode++] = *nIt;
9122     }
9123     for(i=1; i<nbn; i++) {
9124       SMDS_MeshElement* newElem =
9125         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9126       myLastCreatedElems.Append(newElem);
9127       if ( aShapeId && newElem )
9128         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9129     }
9130   }
9131   // remove old face
9132   aMesh->RemoveElement(theFace);
9133 }
9134
9135 //=======================================================================
9136 //function : UpdateVolumes
9137 //purpose  :
9138 //=======================================================================
9139 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9140                                       const SMDS_MeshNode*        theBetweenNode2,
9141                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9142 {
9143   myLastCreatedElems.Clear();
9144   myLastCreatedNodes.Clear();
9145
9146   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9147   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9148     const SMDS_MeshElement* elem = invElemIt->next();
9149
9150     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9151     SMDS_VolumeTool aVolume (elem);
9152     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9153       continue;
9154
9155     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9156     int iface, nbFaces = aVolume.NbFaces();
9157     vector<const SMDS_MeshNode *> poly_nodes;
9158     vector<int> quantities (nbFaces);
9159
9160     for (iface = 0; iface < nbFaces; iface++) {
9161       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9162       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9163       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9164
9165       for (int inode = 0; inode < nbFaceNodes; inode++) {
9166         poly_nodes.push_back(faceNodes[inode]);
9167
9168         if (nbInserted == 0) {
9169           if (faceNodes[inode] == theBetweenNode1) {
9170             if (faceNodes[inode + 1] == theBetweenNode2) {
9171               nbInserted = theNodesToInsert.size();
9172
9173               // add nodes to insert
9174               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9175               for (; nIt != theNodesToInsert.end(); nIt++) {
9176                 poly_nodes.push_back(*nIt);
9177               }
9178             }
9179           }
9180           else if (faceNodes[inode] == theBetweenNode2) {
9181             if (faceNodes[inode + 1] == theBetweenNode1) {
9182               nbInserted = theNodesToInsert.size();
9183
9184               // add nodes to insert in reversed order
9185               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9186               nIt--;
9187               for (; nIt != theNodesToInsert.begin(); nIt--) {
9188                 poly_nodes.push_back(*nIt);
9189               }
9190               poly_nodes.push_back(*nIt);
9191             }
9192           }
9193           else {
9194           }
9195         }
9196       }
9197       quantities[iface] = nbFaceNodes + nbInserted;
9198     }
9199
9200     // Replace or update the volume
9201     SMESHDS_Mesh *aMesh = GetMeshDS();
9202
9203     if (elem->IsPoly()) {
9204       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9205
9206     }
9207     else {
9208       int aShapeId = FindShape( elem );
9209
9210       SMDS_MeshElement* newElem =
9211         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9212       myLastCreatedElems.Append(newElem);
9213       if (aShapeId && newElem)
9214         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9215
9216       aMesh->RemoveElement(elem);
9217     }
9218   }
9219 }
9220
9221 //=======================================================================
9222 /*!
9223  * \brief Convert elements contained in a submesh to quadratic
9224  * \return int - nb of checked elements
9225  */
9226 //=======================================================================
9227
9228 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9229                                              SMESH_MesherHelper& theHelper,
9230                                              const bool          theForce3d)
9231 {
9232   int nbElem = 0;
9233   if( !theSm ) return nbElem;
9234
9235   vector<int> nbNodeInFaces;
9236   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9237   while(ElemItr->more())
9238   {
9239     nbElem++;
9240     const SMDS_MeshElement* elem = ElemItr->next();
9241     if( !elem || elem->IsQuadratic() ) continue;
9242
9243     int id = elem->GetID();
9244     int nbNodes = elem->NbNodes();
9245     SMDSAbs_ElementType aType = elem->GetType();
9246
9247     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9248     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9249       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9250
9251     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9252
9253     const SMDS_MeshElement* NewElem = 0;
9254
9255     switch( aType )
9256     {
9257     case SMDSAbs_Edge :
9258       {
9259         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9260         break;
9261       }
9262     case SMDSAbs_Face :
9263       {
9264         switch(nbNodes)
9265         {
9266         case 3:
9267           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9268           break;
9269         case 4:
9270           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9271           break;
9272         default:
9273           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9274           continue;
9275         }
9276         break;
9277       }
9278     case SMDSAbs_Volume :
9279       {
9280         switch(nbNodes)
9281         {
9282         case 4:
9283           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9284           break;
9285         case 5:
9286           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9287           break;
9288         case 6:
9289           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9290           break;
9291         case 8:
9292           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9293                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9294           break;
9295         default:
9296           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9297         }
9298         break;
9299       }
9300     default :
9301       continue;
9302     }
9303     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9304     if( NewElem )
9305       theSm->AddElement( NewElem );
9306   }
9307 //  if (!GetMeshDS()->isCompacted())
9308 //    GetMeshDS()->compactMesh();
9309   return nbElem;
9310 }
9311
9312 //=======================================================================
9313 //function : ConvertToQuadratic
9314 //purpose  :
9315 //=======================================================================
9316 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9317 {
9318   SMESHDS_Mesh* meshDS = GetMeshDS();
9319
9320   SMESH_MesherHelper aHelper(*myMesh);
9321   aHelper.SetIsQuadratic( true );
9322
9323   int nbCheckedElems = 0;
9324   if ( myMesh->HasShapeToMesh() )
9325   {
9326     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9327     {
9328       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9329       while ( smIt->more() ) {
9330         SMESH_subMesh* sm = smIt->next();
9331         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9332           aHelper.SetSubShape( sm->GetSubShape() );
9333           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9334         }
9335       }
9336     }
9337   }
9338   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9339   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9340   {
9341     SMESHDS_SubMesh *smDS = 0;
9342     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9343     while(aEdgeItr->more())
9344     {
9345       const SMDS_MeshEdge* edge = aEdgeItr->next();
9346       if(edge && !edge->IsQuadratic())
9347       {
9348         int id = edge->GetID();
9349         //MESSAGE("edge->GetID() " << id);
9350         const SMDS_MeshNode* n1 = edge->GetNode(0);
9351         const SMDS_MeshNode* n2 = edge->GetNode(1);
9352
9353         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9354
9355         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9356         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9357       }
9358     }
9359     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9360     while(aFaceItr->more())
9361     {
9362       const SMDS_MeshFace* face = aFaceItr->next();
9363       if(!face || face->IsQuadratic() ) continue;
9364
9365       int id = face->GetID();
9366       int nbNodes = face->NbNodes();
9367       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9368
9369       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9370
9371       SMDS_MeshFace * NewFace = 0;
9372       switch(nbNodes)
9373       {
9374       case 3:
9375         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9376         break;
9377       case 4:
9378         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9379         break;
9380       default:
9381         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9382       }
9383       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9384     }
9385     vector<int> nbNodeInFaces;
9386     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9387     while(aVolumeItr->more())
9388     {
9389       const SMDS_MeshVolume* volume = aVolumeItr->next();
9390       if(!volume || volume->IsQuadratic() ) continue;
9391
9392       int id = volume->GetID();
9393       int nbNodes = volume->NbNodes();
9394       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9395       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9396         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9397
9398       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9399
9400       SMDS_MeshVolume * NewVolume = 0;
9401       switch(nbNodes)
9402       {
9403       case 4:
9404         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9405                                       nodes[3], id, theForce3d );
9406         break;
9407       case 5:
9408         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9409                                       nodes[3], nodes[4], id, theForce3d);
9410         break;
9411       case 6:
9412         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9413                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9414         break;
9415       case 8:
9416         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9417                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9418         break;
9419       default:
9420         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9421       }
9422       ReplaceElemInGroups(volume, NewVolume, meshDS);
9423     }
9424   }
9425
9426   if ( !theForce3d )
9427   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9428     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9429     aHelper.FixQuadraticElements();
9430   }
9431 }
9432
9433 //================================================================================
9434 /*!
9435  * \brief Makes given elements quadratic
9436  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9437  *  \param theElements - elements to make quadratic 
9438  */
9439 //================================================================================
9440
9441 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9442                                           TIDSortedElemSet& theElements)
9443 {
9444   if ( theElements.empty() ) return;
9445
9446   // we believe that all theElements are of the same type
9447   SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9448   
9449   // get all nodes shared by theElements
9450   TIDSortedNodeSet allNodes;
9451   TIDSortedElemSet::iterator eIt = theElements.begin();
9452   for ( ; eIt != theElements.end(); ++eIt )
9453     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9454
9455   // complete theElements with elements of lower dim whose all nodes are in allNodes
9456
9457   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9458   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9459   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9460   for ( ; nIt != allNodes.end(); ++nIt )
9461   {
9462     const SMDS_MeshNode* n = *nIt;
9463     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9464     while ( invIt->more() )
9465     {
9466       const SMDS_MeshElement* e = invIt->next();
9467       if ( e->IsQuadratic() )
9468       {
9469         quadAdjacentElems[ e->GetType() ].insert( e );
9470         continue;
9471       }
9472       if ( e->GetType() >= elemType )
9473       {
9474         continue; // same type of more complex linear element
9475       }
9476
9477       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9478         continue; // e is already checked
9479
9480       // check nodes
9481       bool allIn = true;
9482       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9483       while ( nodeIt->more() && allIn )
9484         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9485       if ( allIn )
9486         theElements.insert(e );
9487     }
9488   }
9489
9490   SMESH_MesherHelper helper(*myMesh);
9491   helper.SetIsQuadratic( true );
9492
9493   // add links of quadratic adjacent elements to the helper
9494
9495   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9496     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9497           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9498     {
9499       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9500     }
9501   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9502     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9503           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9504     {
9505       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9506     }
9507   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9508     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9509           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9510     {
9511       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9512     }
9513
9514   // make quadratic elements instead of linear ones
9515
9516   SMESHDS_Mesh* meshDS = GetMeshDS();
9517   SMESHDS_SubMesh* smDS = 0;
9518   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9519   {
9520     const SMDS_MeshElement* elem = *eIt;
9521     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9522       continue;
9523
9524     int id = elem->GetID();
9525     SMDSAbs_ElementType type = elem->GetType();
9526     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9527
9528     if ( !smDS || !smDS->Contains( elem ))
9529       smDS = meshDS->MeshElements( elem->getshapeId() );
9530     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9531
9532     SMDS_MeshElement * newElem = 0;
9533     switch( nodes.size() )
9534     {
9535     case 4: // cases for most multiple element types go first (for optimization)
9536       if ( type == SMDSAbs_Volume )
9537         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9538       else
9539         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9540       break;
9541     case 8:
9542       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9543                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9544       break;
9545     case 3:
9546       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9547       break;
9548     case 2:
9549       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9550       break;
9551     case 5:
9552       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9553                                  nodes[4], id, theForce3d);
9554       break;
9555     case 6:
9556       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9557                                  nodes[4], nodes[5], id, theForce3d);
9558       break;
9559     default:;
9560     }
9561     ReplaceElemInGroups( elem, newElem, meshDS);
9562     if( newElem && smDS )
9563       smDS->AddElement( newElem );
9564   }
9565
9566   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9567   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9568     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9569     helper.FixQuadraticElements();
9570   }
9571 }
9572
9573 //=======================================================================
9574 /*!
9575  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9576  * \return int - nb of checked elements
9577  */
9578 //=======================================================================
9579
9580 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9581                                      SMDS_ElemIteratorPtr theItr,
9582                                      const int            theShapeID)
9583 {
9584   int nbElem = 0;
9585   SMESHDS_Mesh* meshDS = GetMeshDS();
9586
9587   while( theItr->more() )
9588   {
9589     const SMDS_MeshElement* elem = theItr->next();
9590     nbElem++;
9591     if( elem && elem->IsQuadratic())
9592     {
9593       int id                    = elem->GetID();
9594       int nbCornerNodes         = elem->NbCornerNodes();
9595       SMDSAbs_ElementType aType = elem->GetType();
9596
9597       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9598
9599       //remove a quadratic element
9600       if ( !theSm || !theSm->Contains( elem ))
9601         theSm = meshDS->MeshElements( elem->getshapeId() );
9602       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9603
9604       // remove medium nodes
9605       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9606         if ( nodes[i]->NbInverseElements() == 0 )
9607           meshDS->RemoveFreeNode( nodes[i], theSm );
9608
9609       // add a linear element
9610       nodes.resize( nbCornerNodes );
9611       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9612       ReplaceElemInGroups(elem, newElem, meshDS);
9613       if( theSm && newElem )
9614         theSm->AddElement( newElem );
9615     }
9616   }
9617   return nbElem;
9618 }
9619
9620 //=======================================================================
9621 //function : ConvertFromQuadratic
9622 //purpose  :
9623 //=======================================================================
9624
9625 bool SMESH_MeshEditor::ConvertFromQuadratic()
9626 {
9627   int nbCheckedElems = 0;
9628   if ( myMesh->HasShapeToMesh() )
9629   {
9630     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9631     {
9632       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9633       while ( smIt->more() ) {
9634         SMESH_subMesh* sm = smIt->next();
9635         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9636           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9637       }
9638     }
9639   }
9640
9641   int totalNbElems =
9642     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9643   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9644   {
9645     SMESHDS_SubMesh *aSM = 0;
9646     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9647   }
9648
9649   return true;
9650 }
9651
9652 namespace
9653 {
9654   //================================================================================
9655   /*!
9656    * \brief Return true if all medium nodes of the element are in the node set
9657    */
9658   //================================================================================
9659
9660   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9661   {
9662     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9663       if ( !nodeSet.count( elem->GetNode(i) ))
9664         return false;
9665     return true;
9666   }
9667 }
9668
9669 //================================================================================
9670 /*!
9671  * \brief Makes given elements linear
9672  */
9673 //================================================================================
9674
9675 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9676 {
9677   if ( theElements.empty() ) return;
9678
9679   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9680   set<int> mediumNodeIDs;
9681   TIDSortedElemSet::iterator eIt = theElements.begin();
9682   for ( ; eIt != theElements.end(); ++eIt )
9683   {
9684     const SMDS_MeshElement* e = *eIt;
9685     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9686       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9687   }
9688
9689   // replace given elements by linear ones
9690   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9691   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9692   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9693
9694   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9695   // except those elements sharing medium nodes of quadratic element whose medium nodes
9696   // are not all in mediumNodeIDs
9697
9698   // get remaining medium nodes
9699   TIDSortedNodeSet mediumNodes;
9700   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9701   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9702     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9703       mediumNodes.insert( mediumNodes.end(), n );
9704
9705   // find more quadratic elements to convert
9706   TIDSortedElemSet moreElemsToConvert;
9707   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9708   for ( ; nIt != mediumNodes.end(); ++nIt )
9709   {
9710     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9711     while ( invIt->more() )
9712     {
9713       const SMDS_MeshElement* e = invIt->next();
9714       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9715       {
9716         // find a more complex element including e and
9717         // whose medium nodes are not in mediumNodes
9718         bool complexFound = false;
9719         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9720         {
9721           SMDS_ElemIteratorPtr invIt2 =
9722             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9723           while ( invIt2->more() )
9724           {
9725             const SMDS_MeshElement* eComplex = invIt2->next();
9726             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9727             {
9728               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9729               if ( nbCommonNodes == e->NbNodes())
9730               {
9731                 complexFound = true;
9732                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9733                 break;
9734               }
9735             }
9736           }
9737         }
9738         if ( !complexFound )
9739           moreElemsToConvert.insert( e );
9740       }
9741     }
9742   }
9743   elemIt = SMDS_ElemIteratorPtr
9744     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9745   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9746 }
9747
9748 //=======================================================================
9749 //function : SewSideElements
9750 //purpose  :
9751 //=======================================================================
9752
9753 SMESH_MeshEditor::Sew_Error
9754 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9755                                    TIDSortedElemSet&    theSide2,
9756                                    const SMDS_MeshNode* theFirstNode1,
9757                                    const SMDS_MeshNode* theFirstNode2,
9758                                    const SMDS_MeshNode* theSecondNode1,
9759                                    const SMDS_MeshNode* theSecondNode2)
9760 {
9761   myLastCreatedElems.Clear();
9762   myLastCreatedNodes.Clear();
9763
9764   MESSAGE ("::::SewSideElements()");
9765   if ( theSide1.size() != theSide2.size() )
9766     return SEW_DIFF_NB_OF_ELEMENTS;
9767
9768   Sew_Error aResult = SEW_OK;
9769   // Algo:
9770   // 1. Build set of faces representing each side
9771   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9772   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9773
9774   // =======================================================================
9775   // 1. Build set of faces representing each side:
9776   // =======================================================================
9777   // a. build set of nodes belonging to faces
9778   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9779   // c. create temporary faces representing side of volumes if correspondent
9780   //    face does not exist
9781
9782   SMESHDS_Mesh* aMesh = GetMeshDS();
9783   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9784   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9785   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9786   set<const SMDS_MeshElement*> volSet1,  volSet2;
9787   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9788   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9789   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9790   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9791   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9792   int iSide, iFace, iNode;
9793
9794   list<const SMDS_MeshElement* > tempFaceList;
9795   for ( iSide = 0; iSide < 2; iSide++ ) {
9796     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9797     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9798     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9799     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9800     set<const SMDS_MeshElement*>::iterator vIt;
9801     TIDSortedElemSet::iterator eIt;
9802     set<const SMDS_MeshNode*>::iterator    nIt;
9803
9804     // check that given nodes belong to given elements
9805     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9806     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9807     int firstIndex = -1, secondIndex = -1;
9808     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9809       const SMDS_MeshElement* elem = *eIt;
9810       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9811       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9812       if ( firstIndex > -1 && secondIndex > -1 ) break;
9813     }
9814     if ( firstIndex < 0 || secondIndex < 0 ) {
9815       // we can simply return until temporary faces created
9816       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9817     }
9818
9819     // -----------------------------------------------------------
9820     // 1a. Collect nodes of existing faces
9821     //     and build set of face nodes in order to detect missing
9822     //     faces corresponding to sides of volumes
9823     // -----------------------------------------------------------
9824
9825     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9826
9827     // loop on the given element of a side
9828     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9829       //const SMDS_MeshElement* elem = *eIt;
9830       const SMDS_MeshElement* elem = *eIt;
9831       if ( elem->GetType() == SMDSAbs_Face ) {
9832         faceSet->insert( elem );
9833         set <const SMDS_MeshNode*> faceNodeSet;
9834         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9835         while ( nodeIt->more() ) {
9836           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9837           nodeSet->insert( n );
9838           faceNodeSet.insert( n );
9839         }
9840         setOfFaceNodeSet.insert( faceNodeSet );
9841       }
9842       else if ( elem->GetType() == SMDSAbs_Volume )
9843         volSet->insert( elem );
9844     }
9845     // ------------------------------------------------------------------------------
9846     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9847     // ------------------------------------------------------------------------------
9848
9849     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9850       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9851       while ( fIt->more() ) { // loop on faces sharing a node
9852         const SMDS_MeshElement* f = fIt->next();
9853         if ( faceSet->find( f ) == faceSet->end() ) {
9854           // check if all nodes are in nodeSet and
9855           // complete setOfFaceNodeSet if they are
9856           set <const SMDS_MeshNode*> faceNodeSet;
9857           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9858           bool allInSet = true;
9859           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9860             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9861             if ( nodeSet->find( n ) == nodeSet->end() )
9862               allInSet = false;
9863             else
9864               faceNodeSet.insert( n );
9865           }
9866           if ( allInSet ) {
9867             faceSet->insert( f );
9868             setOfFaceNodeSet.insert( faceNodeSet );
9869           }
9870         }
9871       }
9872     }
9873
9874     // -------------------------------------------------------------------------
9875     // 1c. Create temporary faces representing sides of volumes if correspondent
9876     //     face does not exist
9877     // -------------------------------------------------------------------------
9878
9879     if ( !volSet->empty() ) {
9880       //int nodeSetSize = nodeSet->size();
9881
9882       // loop on given volumes
9883       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9884         SMDS_VolumeTool vol (*vIt);
9885         // loop on volume faces: find free faces
9886         // --------------------------------------
9887         list<const SMDS_MeshElement* > freeFaceList;
9888         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9889           if ( !vol.IsFreeFace( iFace ))
9890             continue;
9891           // check if there is already a face with same nodes in a face set
9892           const SMDS_MeshElement* aFreeFace = 0;
9893           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9894           int nbNodes = vol.NbFaceNodes( iFace );
9895           set <const SMDS_MeshNode*> faceNodeSet;
9896           vol.GetFaceNodes( iFace, faceNodeSet );
9897           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9898           if ( isNewFace ) {
9899             // no such a face is given but it still can exist, check it
9900             if ( nbNodes == 3 ) {
9901               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9902             }
9903             else if ( nbNodes == 4 ) {
9904               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9905             }
9906             else {
9907               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9908               aFreeFace = aMesh->FindFace(poly_nodes);
9909             }
9910           }
9911           if ( !aFreeFace ) {
9912             // create a temporary face
9913             if ( nbNodes == 3 ) {
9914               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9915               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9916             }
9917             else if ( nbNodes == 4 ) {
9918               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9919               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9920             }
9921             else {
9922               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9923               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9924               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9925             }
9926           }
9927           if ( aFreeFace ) {
9928             freeFaceList.push_back( aFreeFace );
9929             tempFaceList.push_back( aFreeFace );
9930           }
9931
9932         } // loop on faces of a volume
9933
9934         // choose one of several free faces
9935         // --------------------------------------
9936         if ( freeFaceList.size() > 1 ) {
9937           // choose a face having max nb of nodes shared by other elems of a side
9938           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9939           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9940           while ( fIt != freeFaceList.end() ) { // loop on free faces
9941             int nbSharedNodes = 0;
9942             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9943             while ( nodeIt->more() ) { // loop on free face nodes
9944               const SMDS_MeshNode* n =
9945                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9946               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9947               while ( invElemIt->more() ) {
9948                 const SMDS_MeshElement* e = invElemIt->next();
9949                 if ( faceSet->find( e ) != faceSet->end() )
9950                   nbSharedNodes++;
9951                 if ( elemSet->find( e ) != elemSet->end() )
9952                   nbSharedNodes++;
9953               }
9954             }
9955             if ( nbSharedNodes >= maxNbNodes ) {
9956               maxNbNodes = nbSharedNodes;
9957               fIt++;
9958             }
9959             else
9960               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9961           }
9962           if ( freeFaceList.size() > 1 )
9963           {
9964             // could not choose one face, use another way
9965             // choose a face most close to the bary center of the opposite side
9966             gp_XYZ aBC( 0., 0., 0. );
9967             set <const SMDS_MeshNode*> addedNodes;
9968             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9969             eIt = elemSet2->begin();
9970             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9971               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9972               while ( nodeIt->more() ) { // loop on free face nodes
9973                 const SMDS_MeshNode* n =
9974                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9975                 if ( addedNodes.insert( n ).second )
9976                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9977               }
9978             }
9979             aBC /= addedNodes.size();
9980             double minDist = DBL_MAX;
9981             fIt = freeFaceList.begin();
9982             while ( fIt != freeFaceList.end() ) { // loop on free faces
9983               double dist = 0;
9984               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9985               while ( nodeIt->more() ) { // loop on free face nodes
9986                 const SMDS_MeshNode* n =
9987                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9988                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9989                 dist += ( aBC - p ).SquareModulus();
9990               }
9991               if ( dist < minDist ) {
9992                 minDist = dist;
9993                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9994               }
9995               else
9996                 fIt = freeFaceList.erase( fIt++ );
9997             }
9998           }
9999         } // choose one of several free faces of a volume
10000
10001         if ( freeFaceList.size() == 1 ) {
10002           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
10003           faceSet->insert( aFreeFace );
10004           // complete a node set with nodes of a found free face
10005           //           for ( iNode = 0; iNode < ; iNode++ )
10006           //             nodeSet->insert( fNodes[ iNode ] );
10007         }
10008
10009       } // loop on volumes of a side
10010
10011       //       // complete a set of faces if new nodes in a nodeSet appeared
10012       //       // ----------------------------------------------------------
10013       //       if ( nodeSetSize != nodeSet->size() ) {
10014       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10015       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10016       //           while ( fIt->more() ) { // loop on faces sharing a node
10017       //             const SMDS_MeshElement* f = fIt->next();
10018       //             if ( faceSet->find( f ) == faceSet->end() ) {
10019       //               // check if all nodes are in nodeSet and
10020       //               // complete setOfFaceNodeSet if they are
10021       //               set <const SMDS_MeshNode*> faceNodeSet;
10022       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10023       //               bool allInSet = true;
10024       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10025       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10026       //                 if ( nodeSet->find( n ) == nodeSet->end() )
10027       //                   allInSet = false;
10028       //                 else
10029       //                   faceNodeSet.insert( n );
10030       //               }
10031       //               if ( allInSet ) {
10032       //                 faceSet->insert( f );
10033       //                 setOfFaceNodeSet.insert( faceNodeSet );
10034       //               }
10035       //             }
10036       //           }
10037       //         }
10038       //       }
10039     } // Create temporary faces, if there are volumes given
10040   } // loop on sides
10041
10042   if ( faceSet1.size() != faceSet2.size() ) {
10043     // delete temporary faces: they are in reverseElements of actual nodes
10044 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10045 //    while ( tmpFaceIt->more() )
10046 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10047 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10048 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10049 //      aMesh->RemoveElement(*tmpFaceIt);
10050     MESSAGE("Diff nb of faces");
10051     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10052   }
10053
10054   // ============================================================
10055   // 2. Find nodes to merge:
10056   //              bind a node to remove to a node to put instead
10057   // ============================================================
10058
10059   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10060   if ( theFirstNode1 != theFirstNode2 )
10061     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10062   if ( theSecondNode1 != theSecondNode2 )
10063     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10064
10065   LinkID_Gen aLinkID_Gen( GetMeshDS() );
10066   set< long > linkIdSet; // links to process
10067   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10068
10069   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10070   list< NLink > linkList[2];
10071   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10072   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10073   // loop on links in linkList; find faces by links and append links
10074   // of the found faces to linkList
10075   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10076   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10077     NLink link[] = { *linkIt[0], *linkIt[1] };
10078     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10079     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10080       continue;
10081
10082     // by links, find faces in the face sets,
10083     // and find indices of link nodes in the found faces;
10084     // in a face set, there is only one or no face sharing a link
10085     // ---------------------------------------------------------------
10086
10087     const SMDS_MeshElement* face[] = { 0, 0 };
10088     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10089     vector<const SMDS_MeshNode*> fnodes1(9);
10090     vector<const SMDS_MeshNode*> fnodes2(9);
10091     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10092     vector<const SMDS_MeshNode*> notLinkNodes1(6);
10093     vector<const SMDS_MeshNode*> notLinkNodes2(6);
10094     int iLinkNode[2][2];
10095     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10096       const SMDS_MeshNode* n1 = link[iSide].first;
10097       const SMDS_MeshNode* n2 = link[iSide].second;
10098       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10099       set< const SMDS_MeshElement* > fMap;
10100       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10101         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10102         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10103         while ( fIt->more() ) { // loop on faces sharing a node
10104           const SMDS_MeshElement* f = fIt->next();
10105           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10106               ! fMap.insert( f ).second ) // f encounters twice
10107           {
10108             if ( face[ iSide ] ) {
10109               MESSAGE( "2 faces per link " );
10110               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10111               break;
10112             }
10113             face[ iSide ] = f;
10114             faceSet->erase( f );
10115             // get face nodes and find ones of a link
10116             iNode = 0;
10117             int nbl = -1;
10118             if(f->IsPoly()) {
10119               if(iSide==0) {
10120                 fnodes1.resize(f->NbNodes()+1);
10121                 notLinkNodes1.resize(f->NbNodes()-2);
10122               }
10123               else {
10124                 fnodes2.resize(f->NbNodes()+1);
10125                 notLinkNodes2.resize(f->NbNodes()-2);
10126               }
10127             }
10128             if(!f->IsQuadratic()) {
10129               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10130               while ( nIt->more() ) {
10131                 const SMDS_MeshNode* n =
10132                   static_cast<const SMDS_MeshNode*>( nIt->next() );
10133                 if ( n == n1 ) {
10134                   iLinkNode[ iSide ][ 0 ] = iNode;
10135                 }
10136                 else if ( n == n2 ) {
10137                   iLinkNode[ iSide ][ 1 ] = iNode;
10138                 }
10139                 //else if ( notLinkNodes[ iSide ][ 0 ] )
10140                 //  notLinkNodes[ iSide ][ 1 ] = n;
10141                 //else
10142                 //  notLinkNodes[ iSide ][ 0 ] = n;
10143                 else {
10144                   nbl++;
10145                   if(iSide==0)
10146                     notLinkNodes1[nbl] = n;
10147                   //notLinkNodes1.push_back(n);
10148                   else
10149                     notLinkNodes2[nbl] = n;
10150                   //notLinkNodes2.push_back(n);
10151                 }
10152                 //faceNodes[ iSide ][ iNode++ ] = n;
10153                 if(iSide==0) {
10154                   fnodes1[iNode++] = n;
10155                 }
10156                 else {
10157                   fnodes2[iNode++] = n;
10158                 }
10159               }
10160             }
10161             else { // f->IsQuadratic()
10162               const SMDS_VtkFace* F =
10163                 dynamic_cast<const SMDS_VtkFace*>(f);
10164               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10165               // use special nodes iterator
10166               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10167               while ( anIter->more() ) {
10168                 const SMDS_MeshNode* n =
10169                   static_cast<const SMDS_MeshNode*>( anIter->next() );
10170                 if ( n == n1 ) {
10171                   iLinkNode[ iSide ][ 0 ] = iNode;
10172                 }
10173                 else if ( n == n2 ) {
10174                   iLinkNode[ iSide ][ 1 ] = iNode;
10175                 }
10176                 else {
10177                   nbl++;
10178                   if(iSide==0) {
10179                     notLinkNodes1[nbl] = n;
10180                   }
10181                   else {
10182                     notLinkNodes2[nbl] = n;
10183                   }
10184                 }
10185                 if(iSide==0) {
10186                   fnodes1[iNode++] = n;
10187                 }
10188                 else {
10189                   fnodes2[iNode++] = n;
10190                 }
10191               }
10192             }
10193             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10194             if(iSide==0) {
10195               fnodes1[iNode] = fnodes1[0];
10196             }
10197             else {
10198               fnodes2[iNode] = fnodes1[0];
10199             }
10200           }
10201         }
10202       }
10203     }
10204
10205     // check similarity of elements of the sides
10206     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10207       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10208       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10209         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10210       }
10211       else {
10212         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10213       }
10214       break; // do not return because it s necessary to remove tmp faces
10215     }
10216
10217     // set nodes to merge
10218     // -------------------
10219
10220     if ( face[0] && face[1] )  {
10221       int nbNodes = face[0]->NbNodes();
10222       if ( nbNodes != face[1]->NbNodes() ) {
10223         MESSAGE("Diff nb of face nodes");
10224         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10225         break; // do not return because it s necessary to remove tmp faces
10226       }
10227       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10228       if ( nbNodes == 3 ) {
10229         //nReplaceMap.insert( TNodeNodeMap::value_type
10230         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10231         nReplaceMap.insert( TNodeNodeMap::value_type
10232                             ( notLinkNodes1[0], notLinkNodes2[0] ));
10233       }
10234       else {
10235         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10236           // analyse link orientation in faces
10237           int i1 = iLinkNode[ iSide ][ 0 ];
10238           int i2 = iLinkNode[ iSide ][ 1 ];
10239           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10240           // if notLinkNodes are the first and the last ones, then
10241           // their order does not correspond to the link orientation
10242           if (( i1 == 1 && i2 == 2 ) ||
10243               ( i1 == 2 && i2 == 1 ))
10244             reverse[ iSide ] = !reverse[ iSide ];
10245         }
10246         if ( reverse[0] == reverse[1] ) {
10247           //nReplaceMap.insert( TNodeNodeMap::value_type
10248           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10249           //nReplaceMap.insert( TNodeNodeMap::value_type
10250           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10251           for(int nn=0; nn<nbNodes-2; nn++) {
10252             nReplaceMap.insert( TNodeNodeMap::value_type
10253                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10254           }
10255         }
10256         else {
10257           //nReplaceMap.insert( TNodeNodeMap::value_type
10258           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10259           //nReplaceMap.insert( TNodeNodeMap::value_type
10260           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10261           for(int nn=0; nn<nbNodes-2; nn++) {
10262             nReplaceMap.insert( TNodeNodeMap::value_type
10263                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10264           }
10265         }
10266       }
10267
10268       // add other links of the faces to linkList
10269       // -----------------------------------------
10270
10271       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10272       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10273         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10274         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10275         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10276         if ( !iter_isnew.second ) { // already in a set: no need to process
10277           linkIdSet.erase( iter_isnew.first );
10278         }
10279         else // new in set == encountered for the first time: add
10280         {
10281           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10282           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10283           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10284           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10285           linkList[0].push_back ( NLink( n1, n2 ));
10286           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10287         }
10288       }
10289     } // 2 faces found
10290   } // loop on link lists
10291
10292   if ( aResult == SEW_OK &&
10293        ( linkIt[0] != linkList[0].end() ||
10294          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10295     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10296              " " << (faceSetPtr[1]->empty()));
10297     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10298   }
10299
10300   // ====================================================================
10301   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10302   // ====================================================================
10303
10304   // delete temporary faces: they are in reverseElements of actual nodes
10305 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10306 //  while ( tmpFaceIt->more() )
10307 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10308 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10309 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10310 //    aMesh->RemoveElement(*tmpFaceIt);
10311
10312   if ( aResult != SEW_OK)
10313     return aResult;
10314
10315   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10316   // loop on nodes replacement map
10317   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10318   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10319     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10320       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10321       nodeIDsToRemove.push_back( nToRemove->GetID() );
10322       // loop on elements sharing nToRemove
10323       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10324       while ( invElemIt->more() ) {
10325         const SMDS_MeshElement* e = invElemIt->next();
10326         // get a new suite of nodes: make replacement
10327         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10328         vector< const SMDS_MeshNode*> nodes( nbNodes );
10329         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10330         while ( nIt->more() ) {
10331           const SMDS_MeshNode* n =
10332             static_cast<const SMDS_MeshNode*>( nIt->next() );
10333           nnIt = nReplaceMap.find( n );
10334           if ( nnIt != nReplaceMap.end() ) {
10335             nbReplaced++;
10336             n = (*nnIt).second;
10337           }
10338           nodes[ i++ ] = n;
10339         }
10340         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10341         //         elemIDsToRemove.push_back( e->GetID() );
10342         //       else
10343         if ( nbReplaced )
10344           {
10345             SMDSAbs_ElementType etyp = e->GetType();
10346             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10347             if (newElem)
10348               {
10349                 myLastCreatedElems.Append(newElem);
10350                 AddToSameGroups(newElem, e, aMesh);
10351                 int aShapeId = e->getshapeId();
10352                 if ( aShapeId )
10353                   {
10354                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10355                   }
10356               }
10357             aMesh->RemoveElement(e);
10358           }
10359       }
10360     }
10361
10362   Remove( nodeIDsToRemove, true );
10363
10364   return aResult;
10365 }
10366
10367 //================================================================================
10368 /*!
10369  * \brief Find corresponding nodes in two sets of faces
10370  * \param theSide1 - first face set
10371  * \param theSide2 - second first face
10372  * \param theFirstNode1 - a boundary node of set 1
10373  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10374  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10375  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10376  * \param nReplaceMap - output map of corresponding nodes
10377  * \return bool  - is a success or not
10378  */
10379 //================================================================================
10380
10381 #ifdef _DEBUG_
10382 //#define DEBUG_MATCHING_NODES
10383 #endif
10384
10385 SMESH_MeshEditor::Sew_Error
10386 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10387                                     set<const SMDS_MeshElement*>& theSide2,
10388                                     const SMDS_MeshNode*          theFirstNode1,
10389                                     const SMDS_MeshNode*          theFirstNode2,
10390                                     const SMDS_MeshNode*          theSecondNode1,
10391                                     const SMDS_MeshNode*          theSecondNode2,
10392                                     TNodeNodeMap &                nReplaceMap)
10393 {
10394   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10395
10396   nReplaceMap.clear();
10397   if ( theFirstNode1 != theFirstNode2 )
10398     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10399   if ( theSecondNode1 != theSecondNode2 )
10400     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10401
10402   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10403   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10404
10405   list< NLink > linkList[2];
10406   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10407   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10408
10409   // loop on links in linkList; find faces by links and append links
10410   // of the found faces to linkList
10411   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10412   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10413     NLink link[] = { *linkIt[0], *linkIt[1] };
10414     if ( linkSet.find( link[0] ) == linkSet.end() )
10415       continue;
10416
10417     // by links, find faces in the face sets,
10418     // and find indices of link nodes in the found faces;
10419     // in a face set, there is only one or no face sharing a link
10420     // ---------------------------------------------------------------
10421
10422     const SMDS_MeshElement* face[] = { 0, 0 };
10423     list<const SMDS_MeshNode*> notLinkNodes[2];
10424     //bool reverse[] = { false, false }; // order of notLinkNodes
10425     int nbNodes[2];
10426     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10427     {
10428       const SMDS_MeshNode* n1 = link[iSide].first;
10429       const SMDS_MeshNode* n2 = link[iSide].second;
10430       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10431       set< const SMDS_MeshElement* > facesOfNode1;
10432       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10433       {
10434         // during a loop of the first node, we find all faces around n1,
10435         // during a loop of the second node, we find one face sharing both n1 and n2
10436         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10437         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10438         while ( fIt->more() ) { // loop on faces sharing a node
10439           const SMDS_MeshElement* f = fIt->next();
10440           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10441               ! facesOfNode1.insert( f ).second ) // f encounters twice
10442           {
10443             if ( face[ iSide ] ) {
10444               MESSAGE( "2 faces per link " );
10445               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10446             }
10447             face[ iSide ] = f;
10448             faceSet->erase( f );
10449
10450             // get not link nodes
10451             int nbN = f->NbNodes();
10452             if ( f->IsQuadratic() )
10453               nbN /= 2;
10454             nbNodes[ iSide ] = nbN;
10455             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10456             int i1 = f->GetNodeIndex( n1 );
10457             int i2 = f->GetNodeIndex( n2 );
10458             int iEnd = nbN, iBeg = -1, iDelta = 1;
10459             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10460             if ( reverse ) {
10461               std::swap( iEnd, iBeg ); iDelta = -1;
10462             }
10463             int i = i2;
10464             while ( true ) {
10465               i += iDelta;
10466               if ( i == iEnd ) i = iBeg + iDelta;
10467               if ( i == i1 ) break;
10468               nodes.push_back ( f->GetNode( i ) );
10469             }
10470           }
10471         }
10472       }
10473     }
10474     // check similarity of elements of the sides
10475     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10476       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10477       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10478         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10479       }
10480       else {
10481         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10482       }
10483     }
10484
10485     // set nodes to merge
10486     // -------------------
10487
10488     if ( face[0] && face[1] )  {
10489       if ( nbNodes[0] != nbNodes[1] ) {
10490         MESSAGE("Diff nb of face nodes");
10491         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10492       }
10493 #ifdef DEBUG_MATCHING_NODES
10494       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10495                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10496                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10497 #endif
10498       int nbN = nbNodes[0];
10499       {
10500         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10501         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10502         for ( int i = 0 ; i < nbN - 2; ++i ) {
10503 #ifdef DEBUG_MATCHING_NODES
10504           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10505 #endif
10506           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10507         }
10508       }
10509
10510       // add other links of the face 1 to linkList
10511       // -----------------------------------------
10512
10513       const SMDS_MeshElement* f0 = face[0];
10514       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10515       for ( int i = 0; i < nbN; i++ )
10516       {
10517         const SMDS_MeshNode* n2 = f0->GetNode( i );
10518         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10519           linkSet.insert( SMESH_TLink( n1, n2 ));
10520         if ( !iter_isnew.second ) { // already in a set: no need to process
10521           linkSet.erase( iter_isnew.first );
10522         }
10523         else // new in set == encountered for the first time: add
10524         {
10525 #ifdef DEBUG_MATCHING_NODES
10526           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10527                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10528 #endif
10529           linkList[0].push_back ( NLink( n1, n2 ));
10530           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10531         }
10532         n1 = n2;
10533       }
10534     } // 2 faces found
10535   } // loop on link lists
10536
10537   return SEW_OK;
10538 }
10539
10540 //================================================================================
10541 /*!
10542   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10543   \param theElems - the list of elements (edges or faces) to be replicated
10544   The nodes for duplication could be found from these elements
10545   \param theNodesNot - list of nodes to NOT replicate
10546   \param theAffectedElems - the list of elements (cells and edges) to which the 
10547   replicated nodes should be associated to.
10548   \return TRUE if operation has been completed successfully, FALSE otherwise
10549 */
10550 //================================================================================
10551
10552 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10553                                     const TIDSortedElemSet& theNodesNot,
10554                                     const TIDSortedElemSet& theAffectedElems )
10555 {
10556   myLastCreatedElems.Clear();
10557   myLastCreatedNodes.Clear();
10558
10559   if ( theElems.size() == 0 )
10560     return false;
10561
10562   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10563   if ( !aMeshDS )
10564     return false;
10565
10566   bool res = false;
10567   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10568   // duplicate elements and nodes
10569   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10570   // replce nodes by duplications
10571   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10572   return res;
10573 }
10574
10575 //================================================================================
10576 /*!
10577   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10578   \param theMeshDS - mesh instance
10579   \param theElems - the elements replicated or modified (nodes should be changed)
10580   \param theNodesNot - nodes to NOT replicate
10581   \param theNodeNodeMap - relation of old node to new created node
10582   \param theIsDoubleElem - flag os to replicate element or modify
10583   \return TRUE if operation has been completed successfully, FALSE otherwise
10584 */
10585 //================================================================================
10586
10587 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10588                                     const TIDSortedElemSet& theElems,
10589                                     const TIDSortedElemSet& theNodesNot,
10590                                     std::map< const SMDS_MeshNode*,
10591                                     const SMDS_MeshNode* >& theNodeNodeMap,
10592                                     const bool theIsDoubleElem )
10593 {
10594   MESSAGE("doubleNodes");
10595   // iterate on through element and duplicate them (by nodes duplication)
10596   bool res = false;
10597   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10598   for ( ;  elemItr != theElems.end(); ++elemItr )
10599   {
10600     const SMDS_MeshElement* anElem = *elemItr;
10601     if (!anElem)
10602       continue;
10603
10604     bool isDuplicate = false;
10605     // duplicate nodes to duplicate element
10606     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10607     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10608     int ind = 0;
10609     while ( anIter->more() ) 
10610     { 
10611
10612       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10613       SMDS_MeshNode* aNewNode = aCurrNode;
10614       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10615         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10616       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10617       {
10618         // duplicate node
10619         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10620         theNodeNodeMap[ aCurrNode ] = aNewNode;
10621         myLastCreatedNodes.Append( aNewNode );
10622       }
10623       isDuplicate |= (aCurrNode != aNewNode);
10624       newNodes[ ind++ ] = aNewNode;
10625     }
10626     if ( !isDuplicate )
10627       continue;
10628
10629     if ( theIsDoubleElem )
10630       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10631     else
10632       {
10633       MESSAGE("ChangeElementNodes");
10634       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10635       }
10636     res = true;
10637   }
10638   return res;
10639 }
10640
10641 //================================================================================
10642 /*!
10643   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10644   \param theNodes - identifiers of nodes to be doubled
10645   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10646          nodes. If list of element identifiers is empty then nodes are doubled but 
10647          they not assigned to elements
10648   \return TRUE if operation has been completed successfully, FALSE otherwise
10649 */
10650 //================================================================================
10651
10652 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10653                                     const std::list< int >& theListOfModifiedElems )
10654 {
10655   MESSAGE("DoubleNodes");
10656   myLastCreatedElems.Clear();
10657   myLastCreatedNodes.Clear();
10658
10659   if ( theListOfNodes.size() == 0 )
10660     return false;
10661
10662   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10663   if ( !aMeshDS )
10664     return false;
10665
10666   // iterate through nodes and duplicate them
10667
10668   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10669
10670   std::list< int >::const_iterator aNodeIter;
10671   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10672   {
10673     int aCurr = *aNodeIter;
10674     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10675     if ( !aNode )
10676       continue;
10677
10678     // duplicate node
10679
10680     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10681     if ( aNewNode )
10682     {
10683       anOldNodeToNewNode[ aNode ] = aNewNode;
10684       myLastCreatedNodes.Append( aNewNode );
10685     }
10686   }
10687
10688   // Create map of new nodes for modified elements
10689
10690   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10691
10692   std::list< int >::const_iterator anElemIter;
10693   for ( anElemIter = theListOfModifiedElems.begin(); 
10694         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10695   {
10696     int aCurr = *anElemIter;
10697     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10698     if ( !anElem )
10699       continue;
10700
10701     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10702
10703     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10704     int ind = 0;
10705     while ( anIter->more() ) 
10706     { 
10707       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10708       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10709       {
10710         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10711         aNodeArr[ ind++ ] = aNewNode;
10712       }
10713       else
10714         aNodeArr[ ind++ ] = aCurrNode;
10715     }
10716     anElemToNodes[ anElem ] = aNodeArr;
10717   }
10718
10719   // Change nodes of elements  
10720
10721   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10722     anElemToNodesIter = anElemToNodes.begin();
10723   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10724   {
10725     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10726     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10727     if ( anElem )
10728       {
10729       MESSAGE("ChangeElementNodes");
10730       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10731       }
10732   }
10733
10734   return true;
10735 }
10736
10737 namespace {
10738
10739   //================================================================================
10740   /*!
10741   \brief Check if element located inside shape
10742   \return TRUE if IN or ON shape, FALSE otherwise
10743   */
10744   //================================================================================
10745
10746   template<class Classifier>
10747   bool isInside(const SMDS_MeshElement* theElem,
10748                 Classifier&             theClassifier,
10749                 const double            theTol)
10750   {
10751     gp_XYZ centerXYZ (0, 0, 0);
10752     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10753     while (aNodeItr->more())
10754       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10755
10756     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10757     theClassifier.Perform(aPnt, theTol);
10758     TopAbs_State aState = theClassifier.State();
10759     return (aState == TopAbs_IN || aState == TopAbs_ON );
10760   }
10761
10762   //================================================================================
10763   /*!
10764    * \brief Classifier of the 3D point on the TopoDS_Face
10765    *        with interaface suitable for isInside()
10766    */
10767   //================================================================================
10768
10769   struct _FaceClassifier
10770   {
10771     Extrema_ExtPS       _extremum;
10772     BRepAdaptor_Surface _surface;
10773     TopAbs_State        _state;
10774
10775     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10776     {
10777       _extremum.Initialize( _surface,
10778                             _surface.FirstUParameter(), _surface.LastUParameter(),
10779                             _surface.FirstVParameter(), _surface.LastVParameter(),
10780                             _surface.Tolerance(), _surface.Tolerance() );
10781     }
10782     void Perform(const gp_Pnt& aPnt, double theTol)
10783     {
10784       _state = TopAbs_OUT;
10785       _extremum.Perform(aPnt);
10786       if ( _extremum.IsDone() )
10787         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10788           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10789     }
10790     TopAbs_State State() const
10791     {
10792       return _state;
10793     }
10794   };
10795 }
10796
10797 //================================================================================
10798 /*!
10799   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10800   \param theElems - group of of elements (edges or faces) to be replicated
10801   \param theNodesNot - group of nodes not to replicate
10802   \param theShape - shape to detect affected elements (element which geometric center
10803   located on or inside shape).
10804   The replicated nodes should be associated to affected elements.
10805   \return TRUE if operation has been completed successfully, FALSE otherwise
10806 */
10807 //================================================================================
10808
10809 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10810                                             const TIDSortedElemSet& theNodesNot,
10811                                             const TopoDS_Shape&     theShape )
10812 {
10813   if ( theShape.IsNull() )
10814     return false;
10815
10816   const double aTol = Precision::Confusion();
10817   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10818   auto_ptr<_FaceClassifier>              aFaceClassifier;
10819   if ( theShape.ShapeType() == TopAbs_SOLID )
10820   {
10821     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10822     bsc3d->PerformInfinitePoint(aTol);
10823   }
10824   else if (theShape.ShapeType() == TopAbs_FACE )
10825   {
10826     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10827   }
10828
10829   // iterates on indicated elements and get elements by back references from their nodes
10830   TIDSortedElemSet anAffected;
10831   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10832   for ( ;  elemItr != theElems.end(); ++elemItr )
10833   {
10834     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10835     if (!anElem)
10836       continue;
10837
10838     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10839     while ( nodeItr->more() )
10840     {
10841       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10842       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10843         continue;
10844       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10845       while ( backElemItr->more() )
10846       {
10847         const SMDS_MeshElement* curElem = backElemItr->next();
10848         if ( curElem && theElems.find(curElem) == theElems.end() &&
10849              ( bsc3d.get() ?
10850                isInside( curElem, *bsc3d, aTol ) :
10851                isInside( curElem, *aFaceClassifier, aTol )))
10852           anAffected.insert( curElem );
10853       }
10854     }
10855   }
10856   return DoubleNodes( theElems, theNodesNot, anAffected );
10857 }
10858
10859 /*!
10860  *  \brief compute an oriented angle between two planes defined by four points.
10861  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10862  *  @param p0 base of the rotation axe
10863  *  @param p1 extremity of the rotation axe
10864  *  @param g1 belongs to the first plane
10865  *  @param g2 belongs to the second plane
10866  */
10867 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10868 {
10869 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10870 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10871 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10872 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10873   gp_Vec vref(p0, p1);
10874   gp_Vec v1(p0, g1);
10875   gp_Vec v2(p0, g2);
10876   gp_Vec n1 = vref.Crossed(v1);
10877   gp_Vec n2 = vref.Crossed(v2);
10878   return n2.AngleWithRef(n1, vref);
10879 }
10880
10881 /*!
10882  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10883  * The list of groups must describe a partition of the mesh volumes.
10884  * The nodes of the internal faces at the boundaries of the groups are doubled.
10885  * In option, the internal faces are replaced by flat elements.
10886  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10887  * The flat elements are stored in groups of volumes.
10888  * @param theElems - list of groups of volumes, where a group of volume is a set of
10889  * SMDS_MeshElements sorted by Id.
10890  * @param createJointElems - if TRUE, create the elements
10891  * @return TRUE if operation has been completed successfully, FALSE otherwise
10892  */
10893 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10894                                                      bool createJointElems)
10895 {
10896   MESSAGE("----------------------------------------------");
10897   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10898   MESSAGE("----------------------------------------------");
10899
10900   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10901   meshDS->BuildDownWardConnectivity(true);
10902   CHRONO(50);
10903   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10904
10905   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10906   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10907   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10908
10909   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10910   std::map<int,int>celldom; // cell vtkId --> domain
10911   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10912   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10913   faceDomains.clear();
10914   celldom.clear();
10915   cellDomains.clear();
10916   nodeDomains.clear();
10917   std::map<int,int> emptyMap;
10918   std::set<int> emptySet;
10919   emptyMap.clear();
10920
10921   for (int idom = 0; idom < theElems.size(); idom++)
10922     {
10923
10924       // --- build a map (face to duplicate --> volume to modify)
10925       //     with all the faces shared by 2 domains (group of elements)
10926       //     and corresponding volume of this domain, for each shared face.
10927       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10928
10929       const TIDSortedElemSet& domain = theElems[idom];
10930       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10931       for (; elemItr != domain.end(); ++elemItr)
10932         {
10933           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10934           if (!anElem)
10935             continue;
10936           int vtkId = anElem->getVtkId();
10937           int neighborsVtkIds[NBMAXNEIGHBORS];
10938           int downIds[NBMAXNEIGHBORS];
10939           unsigned char downTypes[NBMAXNEIGHBORS];
10940           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10941           for (int n = 0; n < nbNeighbors; n++)
10942             {
10943               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10944               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10945               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10946                 {
10947                   DownIdType face(downIds[n], downTypes[n]);
10948                   if (!faceDomains.count(face))
10949                     faceDomains[face] = emptyMap; // create an empty entry for face
10950                   if (!faceDomains[face].count(idom))
10951                     {
10952                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10953                       celldom[vtkId] = idom;
10954                     }
10955                 }
10956             }
10957         }
10958     }
10959
10960   //MESSAGE("Number of shared faces " << faceDomains.size());
10961   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10962
10963   // --- explore the shared faces domain by domain,
10964   //     explore the nodes of the face and see if they belong to a cell in the domain,
10965   //     which has only a node or an edge on the border (not a shared face)
10966
10967   for (int idomain = 0; idomain < theElems.size(); idomain++)
10968     {
10969       const TIDSortedElemSet& domain = theElems[idomain];
10970       itface = faceDomains.begin();
10971       for (; itface != faceDomains.end(); ++itface)
10972         {
10973           std::map<int, int> domvol = itface->second;
10974           if (!domvol.count(idomain))
10975             continue;
10976           DownIdType face = itface->first;
10977           //MESSAGE(" --- face " << face.cellId);
10978           std::set<int> oldNodes;
10979           oldNodes.clear();
10980           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10981           std::set<int>::iterator itn = oldNodes.begin();
10982           for (; itn != oldNodes.end(); ++itn)
10983             {
10984               int oldId = *itn;
10985               //MESSAGE("     node " << oldId);
10986               std::set<int> cells;
10987               cells.clear();
10988               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10989               for (int i=0; i<l.ncells; i++)
10990                 {
10991                   int vtkId = l.cells[i];
10992                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10993                   if (!domain.count(anElem))
10994                     continue;
10995                   int vtkType = grid->GetCellType(vtkId);
10996                   int downId = grid->CellIdToDownId(vtkId);
10997                   if (downId < 0)
10998                     {
10999                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
11000                       continue; // not OK at this stage of the algorithm:
11001                                 //no cells created after BuildDownWardConnectivity
11002                     }
11003                   DownIdType aCell(downId, vtkType);
11004                   if (celldom.count(vtkId))
11005                     continue;
11006                   cellDomains[aCell][idomain] = vtkId;
11007                   celldom[vtkId] = idomain;
11008                 }
11009             }
11010         }
11011     }
11012
11013   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
11014   //     for each shared face, get the nodes
11015   //     for each node, for each domain of the face, create a clone of the node
11016
11017   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
11018   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
11019   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
11020
11021   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
11022   std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
11023
11024   for (int idomain = 0; idomain < theElems.size(); idomain++)
11025     {
11026       itface = faceDomains.begin();
11027       for (; itface != faceDomains.end(); ++itface)
11028         {
11029           std::map<int, int> domvol = itface->second;
11030           if (!domvol.count(idomain))
11031             continue;
11032           DownIdType face = itface->first;
11033           //MESSAGE(" --- face " << face.cellId);
11034           std::set<int> oldNodes;
11035           oldNodes.clear();
11036           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11037           bool isMultipleDetected = false;
11038           std::set<int>::iterator itn = oldNodes.begin();
11039           for (; itn != oldNodes.end(); ++itn)
11040             {
11041               int oldId = *itn;
11042               //MESSAGE("     node " << oldId);
11043               if (!nodeDomains.count(oldId))
11044                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11045               if (nodeDomains[oldId].empty())
11046                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11047               std::map<int, int>::iterator itdom = domvol.begin();
11048               for (; itdom != domvol.end(); ++itdom)
11049                 {
11050                   int idom = itdom->first;
11051                   //MESSAGE("         domain " << idom);
11052                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
11053                     {
11054                       if (nodeDomains[oldId].size() >= 2) // a multiple node
11055                         {
11056                           vector<int> orderedDoms;
11057                           //MESSAGE("multiple node " << oldId);
11058                           isMultipleDetected =true;
11059                           if (mutipleNodes.count(oldId))
11060                             orderedDoms = mutipleNodes[oldId];
11061                           else
11062                             {
11063                               map<int,int>::iterator it = nodeDomains[oldId].begin();
11064                               for (; it != nodeDomains[oldId].end(); ++it)
11065                                 orderedDoms.push_back(it->first);
11066                             }
11067                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
11068                           //stringstream txt;
11069                           //for (int i=0; i<orderedDoms.size(); i++)
11070                           //  txt << orderedDoms[i] << " ";
11071                           //MESSAGE("orderedDoms " << txt.str());
11072                           mutipleNodes[oldId] = orderedDoms;
11073                         }
11074                       double *coords = grid->GetPoint(oldId);
11075                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11076                       int newId = newNode->getVtkId();
11077                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
11078                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11079                     }
11080                   if (nodeDomains[oldId].size() >= 3)
11081                     {
11082                       //MESSAGE("confirm multiple node " << oldId);
11083                       isMultipleDetected =true;
11084                     }
11085                 }
11086             }
11087           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11088             {
11089               //MESSAGE("multiple Nodes detected on a shared face");
11090               int downId = itface->first.cellId;
11091               unsigned char cellType = itface->first.cellType;
11092               int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11093               const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11094               const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11095               for (int ie =0; ie < nbEdges; ie++)
11096                 {
11097                   int nodes[3];
11098                   int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11099                   if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11100                     {
11101                       vector<int> vn0 = mutipleNodes[nodes[0]];
11102                       vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11103                       sort( vn0.begin(), vn0.end() );
11104                       sort( vn1.begin(), vn1.end() );
11105                       if (vn0 == vn1)
11106                         {
11107                           //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11108                           double *coords = grid->GetPoint(nodes[0]);
11109                           gp_Pnt p0(coords[0], coords[1], coords[2]);
11110                           coords = grid->GetPoint(nodes[nbNodes - 1]);
11111                           gp_Pnt p1(coords[0], coords[1], coords[2]);
11112                           gp_Pnt gref;
11113                           int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11114                           map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11115                           map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11116                           int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11117                           for (int id=0; id < vn0.size(); id++)
11118                             {
11119                               int idom = vn0[id];
11120                               for (int ivol=0; ivol<nbvol; ivol++)
11121                                 {
11122                                   int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11123                                   SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11124                                   if (theElems[idom].count(elem))
11125                                     {
11126                                       SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11127                                       domvol[idom] = svol;
11128                                       //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11129                                       double values[3];
11130                                       vtkIdType npts = 0;
11131                                       vtkIdType* pts = 0;
11132                                       grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11133                                       SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11134                                       if (id ==0)
11135                                         {
11136                                           gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11137                                           angleDom[idom] = 0;
11138                                         }
11139                                       else
11140                                         {
11141                                           gp_Pnt g(values[0], values[1], values[2]);
11142                                           angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11143                                           //MESSAGE("  angle=" << angleDom[idom]);
11144                                         }
11145                                       break;
11146                                     }
11147                                 }
11148                             }
11149                           map<double, int> sortedDom; // sort domains by angle
11150                           for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11151                             sortedDom[ia->second] = ia->first;
11152                           vector<int> vnodes;
11153                           vector<int> vdom;
11154                           for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11155                             {
11156                               vdom.push_back(ib->second);
11157                               //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11158                             }
11159                           for (int ino = 0; ino < nbNodes; ino++)
11160                             vnodes.push_back(nodes[ino]);
11161                           edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11162                         }
11163                     }
11164                 }
11165             }
11166         }
11167     }
11168
11169   // --- iterate on shared faces (volumes to modify, face to extrude)
11170   //     get node id's of the face (id SMDS = id VTK)
11171   //     create flat element with old and new nodes if requested
11172
11173   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11174   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11175
11176   std::map<int, std::map<long,int> > nodeQuadDomains;
11177   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11178
11179   if (createJointElems)
11180     {
11181       itface = faceDomains.begin();
11182       for (; itface != faceDomains.end(); ++itface)
11183         {
11184           DownIdType face = itface->first;
11185           std::set<int> oldNodes;
11186           std::set<int>::iterator itn;
11187           oldNodes.clear();
11188           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11189
11190           std::map<int, int> domvol = itface->second;
11191           std::map<int, int>::iterator itdom = domvol.begin();
11192           int dom1 = itdom->first;
11193           int vtkVolId = itdom->second;
11194           itdom++;
11195           int dom2 = itdom->first;
11196           SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11197                                                              nodeQuadDomains);
11198           stringstream grpname;
11199           grpname << "j_";
11200           if (dom1 < dom2)
11201             grpname << dom1 << "_" << dom2;
11202           else
11203             grpname << dom2 << "_" << dom1;
11204           int idg;
11205           string namegrp = grpname.str();
11206           if (!mapOfJunctionGroups.count(namegrp))
11207             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11208           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11209           if (sgrp)
11210             sgrp->Add(vol->GetID());
11211         }
11212     }
11213
11214   // --- create volumes on multiple domain intersection if requested
11215   //     iterate on edgesMultiDomains
11216
11217   if (createJointElems)
11218     {
11219       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11220       for (; ite != edgesMultiDomains.end(); ++ite)
11221         {
11222           vector<int> nodes = ite->first;
11223           vector<int> orderDom = ite->second;
11224           vector<vtkIdType> orderedNodes;
11225           if (nodes.size() == 2)
11226             {
11227               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11228               for (int ino=0; ino < nodes.size(); ino++)
11229                 if (orderDom.size() == 3)
11230                   for (int idom = 0; idom <orderDom.size(); idom++)
11231                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11232                 else
11233                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11234                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11235               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11236
11237               stringstream grpname;
11238               grpname << "mj_";
11239               grpname << 0 << "_" << 0;
11240               int idg;
11241               string namegrp = grpname.str();
11242               if (!mapOfJunctionGroups.count(namegrp))
11243                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11244               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11245               if (sgrp)
11246                 sgrp->Add(vol->GetID());
11247             }
11248           else
11249             {
11250               //MESSAGE("Quadratic multiple joints not implemented");
11251               // TODO quadratic nodes
11252             }
11253         }
11254     }
11255
11256   // --- list the explicit faces and edges of the mesh that need to be modified,
11257   //     i.e. faces and edges built with one or more duplicated nodes.
11258   //     associate these faces or edges to their corresponding domain.
11259   //     only the first domain found is kept when a face or edge is shared
11260
11261   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11262   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11263   faceOrEdgeDom.clear();
11264   feDom.clear();
11265
11266   for (int idomain = 0; idomain < theElems.size(); idomain++)
11267     {
11268       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11269       for (; itnod != nodeDomains.end(); ++itnod)
11270         {
11271           int oldId = itnod->first;
11272           //MESSAGE("     node " << oldId);
11273           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11274           for (int i = 0; i < l.ncells; i++)
11275             {
11276               int vtkId = l.cells[i];
11277               int vtkType = grid->GetCellType(vtkId);
11278               int downId = grid->CellIdToDownId(vtkId);
11279               if (downId < 0)
11280                 continue; // new cells: not to be modified
11281               DownIdType aCell(downId, vtkType);
11282               int volParents[1000];
11283               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11284               for (int j = 0; j < nbvol; j++)
11285                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11286                   if (!feDom.count(vtkId))
11287                     {
11288                       feDom[vtkId] = idomain;
11289                       faceOrEdgeDom[aCell] = emptyMap;
11290                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11291                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11292                       //        << " type " << vtkType << " downId " << downId);
11293                     }
11294             }
11295         }
11296     }
11297
11298   // --- iterate on shared faces (volumes to modify, face to extrude)
11299   //     get node id's of the face
11300   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11301
11302   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11303   for (int m=0; m<3; m++)
11304     {
11305       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11306       itface = (*amap).begin();
11307       for (; itface != (*amap).end(); ++itface)
11308         {
11309           DownIdType face = itface->first;
11310           std::set<int> oldNodes;
11311           std::set<int>::iterator itn;
11312           oldNodes.clear();
11313           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11314           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11315           std::map<int, int> localClonedNodeIds;
11316
11317           std::map<int, int> domvol = itface->second;
11318           std::map<int, int>::iterator itdom = domvol.begin();
11319           for (; itdom != domvol.end(); ++itdom)
11320             {
11321               int idom = itdom->first;
11322               int vtkVolId = itdom->second;
11323               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11324               localClonedNodeIds.clear();
11325               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11326                 {
11327                   int oldId = *itn;
11328                   if (nodeDomains[oldId].count(idom))
11329                     {
11330                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11331                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11332                     }
11333                 }
11334               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11335             }
11336         }
11337     }
11338
11339   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11340   grid->BuildLinks();
11341
11342   CHRONOSTOP(50);
11343   counters::stats();
11344   return true;
11345 }
11346
11347 /*!
11348  * \brief Double nodes on some external faces and create flat elements.
11349  * Flat elements are mainly used by some types of mechanic calculations.
11350  *
11351  * Each group of the list must be constituted of faces.
11352  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11353  * @param theElems - list of groups of faces, where a group of faces is a set of
11354  * SMDS_MeshElements sorted by Id.
11355  * @return TRUE if operation has been completed successfully, FALSE otherwise
11356  */
11357 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11358 {
11359   MESSAGE("-------------------------------------------------");
11360   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11361   MESSAGE("-------------------------------------------------");
11362
11363   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11364
11365   // --- For each group of faces
11366   //     duplicate the nodes, create a flat element based on the face
11367   //     replace the nodes of the faces by their clones
11368
11369   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11370   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11371   clonedNodes.clear();
11372   intermediateNodes.clear();
11373   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11374   mapOfJunctionGroups.clear();
11375
11376   for (int idom = 0; idom < theElems.size(); idom++)
11377     {
11378       const TIDSortedElemSet& domain = theElems[idom];
11379       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11380       for (; elemItr != domain.end(); ++elemItr)
11381         {
11382           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11383           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11384           if (!aFace)
11385             continue;
11386           // MESSAGE("aFace=" << aFace->GetID());
11387           bool isQuad = aFace->IsQuadratic();
11388           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11389
11390           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11391
11392           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11393           while (nodeIt->more())
11394             {
11395               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11396               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11397               if (isMedium)
11398                 ln2.push_back(node);
11399               else
11400                 ln0.push_back(node);
11401
11402               const SMDS_MeshNode* clone = 0;
11403               if (!clonedNodes.count(node))
11404                 {
11405                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11406                   clonedNodes[node] = clone;
11407                 }
11408               else
11409                 clone = clonedNodes[node];
11410
11411               if (isMedium)
11412                 ln3.push_back(clone);
11413               else
11414                 ln1.push_back(clone);
11415
11416               const SMDS_MeshNode* inter = 0;
11417               if (isQuad && (!isMedium))
11418                 {
11419                   if (!intermediateNodes.count(node))
11420                     {
11421                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11422                       intermediateNodes[node] = inter;
11423                     }
11424                   else
11425                     inter = intermediateNodes[node];
11426                   ln4.push_back(inter);
11427                 }
11428             }
11429
11430           // --- extrude the face
11431
11432           vector<const SMDS_MeshNode*> ln;
11433           SMDS_MeshVolume* vol = 0;
11434           vtkIdType aType = aFace->GetVtkType();
11435           switch (aType)
11436           {
11437             case VTK_TRIANGLE:
11438               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11439               // MESSAGE("vol prism " << vol->GetID());
11440               ln.push_back(ln1[0]);
11441               ln.push_back(ln1[1]);
11442               ln.push_back(ln1[2]);
11443               break;
11444             case VTK_QUAD:
11445               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11446               // MESSAGE("vol hexa " << vol->GetID());
11447               ln.push_back(ln1[0]);
11448               ln.push_back(ln1[1]);
11449               ln.push_back(ln1[2]);
11450               ln.push_back(ln1[3]);
11451               break;
11452             case VTK_QUADRATIC_TRIANGLE:
11453               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11454                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11455               // MESSAGE("vol quad prism " << vol->GetID());
11456               ln.push_back(ln1[0]);
11457               ln.push_back(ln1[1]);
11458               ln.push_back(ln1[2]);
11459               ln.push_back(ln3[0]);
11460               ln.push_back(ln3[1]);
11461               ln.push_back(ln3[2]);
11462               break;
11463             case VTK_QUADRATIC_QUAD:
11464 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11465 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11466 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11467               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11468                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11469                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11470               // MESSAGE("vol quad hexa " << vol->GetID());
11471               ln.push_back(ln1[0]);
11472               ln.push_back(ln1[1]);
11473               ln.push_back(ln1[2]);
11474               ln.push_back(ln1[3]);
11475               ln.push_back(ln3[0]);
11476               ln.push_back(ln3[1]);
11477               ln.push_back(ln3[2]);
11478               ln.push_back(ln3[3]);
11479               break;
11480             case VTK_POLYGON:
11481               break;
11482             default:
11483               break;
11484           }
11485
11486           if (vol)
11487             {
11488               stringstream grpname;
11489               grpname << "jf_";
11490               grpname << idom;
11491               int idg;
11492               string namegrp = grpname.str();
11493               if (!mapOfJunctionGroups.count(namegrp))
11494                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11495               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11496               if (sgrp)
11497                 sgrp->Add(vol->GetID());
11498             }
11499
11500           // --- modify the face
11501
11502           aFace->ChangeNodes(&ln[0], ln.size());
11503         }
11504     }
11505   return true;
11506 }
11507
11508 //================================================================================
11509 /*!
11510  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11511  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11512  * \return TRUE if operation has been completed successfully, FALSE otherwise
11513  */
11514 //================================================================================
11515
11516 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11517 {
11518   // iterates on volume elements and detect all free faces on them
11519   SMESHDS_Mesh* aMesh = GetMeshDS();
11520   if (!aMesh)
11521     return false;
11522   //bool res = false;
11523   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11524   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11525   while(vIt->more())
11526   {
11527     const SMDS_MeshVolume* volume = vIt->next();
11528     SMDS_VolumeTool vTool( volume );
11529     vTool.SetExternalNormal();
11530     const bool isPoly = volume->IsPoly();
11531     const bool isQuad = volume->IsQuadratic();
11532     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11533     {
11534       if (!vTool.IsFreeFace(iface))
11535         continue;
11536       nbFree++;
11537       vector<const SMDS_MeshNode *> nodes;
11538       int nbFaceNodes = vTool.NbFaceNodes(iface);
11539       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11540       int inode = 0;
11541       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11542         nodes.push_back(faceNodes[inode]);
11543       if (isQuad)
11544         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11545           nodes.push_back(faceNodes[inode]);
11546
11547       // add new face based on volume nodes
11548       if (aMesh->FindFace( nodes ) ) {
11549         nbExisted++;
11550         continue; // face already exsist
11551       }
11552       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11553       nbCreated++;
11554     }
11555   }
11556   return ( nbFree==(nbExisted+nbCreated) );
11557 }
11558
11559 namespace
11560 {
11561   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11562   {
11563     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11564       return n;
11565     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11566   }
11567 }
11568 //================================================================================
11569 /*!
11570  * \brief Creates missing boundary elements
11571  *  \param elements - elements whose boundary is to be checked
11572  *  \param dimension - defines type of boundary elements to create
11573  *  \param group - a group to store created boundary elements in
11574  *  \param targetMesh - a mesh to store created boundary elements in
11575  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11576  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
11577  *                                boundary elements will be copied into the targetMesh
11578  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11579  *                                boundary elements will be added into the new group
11580  *  \param aroundElements - if true, elements will be created on boundary of given
11581  *                          elements else, on boundary of the whole mesh.
11582  * \return nb of added boundary elements
11583  */
11584 //================================================================================
11585
11586 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11587                                        Bnd_Dimension           dimension,
11588                                        SMESH_Group*            group/*=0*/,
11589                                        SMESH_Mesh*             targetMesh/*=0*/,
11590                                        bool                    toCopyElements/*=false*/,
11591                                        bool                    toCopyExistingBoundary/*=false*/,
11592                                        bool                    toAddExistingBondary/*= false*/,
11593                                        bool                    aroundElements/*= false*/)
11594 {
11595   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11596   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11597   // hope that all elements are of the same type, do not check them all
11598   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11599     throw SALOME_Exception(LOCALIZED("wrong element type"));
11600
11601   if ( !targetMesh )
11602     toCopyElements = toCopyExistingBoundary = false;
11603
11604   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11605   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11606   int nbAddedBnd = 0;
11607
11608   // editor adding present bnd elements and optionally holding elements to add to the group
11609   SMESH_MeshEditor* presentEditor;
11610   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11611   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11612
11613   SMDS_VolumeTool vTool;
11614   TIDSortedElemSet avoidSet;
11615   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11616   int inode;
11617
11618   typedef vector<const SMDS_MeshNode*> TConnectivity;
11619
11620   SMDS_ElemIteratorPtr eIt;
11621   if (elements.empty())
11622     eIt = aMesh->elementsIterator(elemType);
11623   else
11624     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11625
11626   while (eIt->more())
11627   {
11628     const SMDS_MeshElement* elem = eIt->next();
11629     const int iQuad = elem->IsQuadratic();
11630
11631     // ------------------------------------------------------------------------------------
11632     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11633     // ------------------------------------------------------------------------------------
11634     vector<const SMDS_MeshElement*> presentBndElems;
11635     vector<TConnectivity>           missingBndElems;
11636     TConnectivity nodes;
11637     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11638     {
11639       vTool.SetExternalNormal();
11640       const SMDS_MeshElement* otherVol = 0;
11641       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11642       {
11643         if ( !vTool.IsFreeFace(iface, &otherVol) &&
11644              ( !aroundElements || elements.count( otherVol )))
11645           continue;
11646         const int nbFaceNodes = vTool.NbFaceNodes(iface);
11647         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11648         if ( missType == SMDSAbs_Edge ) // boundary edges
11649         {
11650           nodes.resize( 2+iQuad );
11651           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11652           {
11653             for ( int j = 0; j < nodes.size(); ++j )
11654               nodes[j] =nn[i+j];
11655             if ( const SMDS_MeshElement* edge =
11656                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11657               presentBndElems.push_back( edge );
11658             else
11659               missingBndElems.push_back( nodes );
11660           }
11661         }
11662         else // boundary face
11663         {
11664           nodes.clear();
11665           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11666             nodes.push_back( nn[inode] );
11667           if (iQuad)
11668             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11669               nodes.push_back( nn[inode] );
11670
11671           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11672             presentBndElems.push_back( f );
11673           else
11674             missingBndElems.push_back( nodes );
11675
11676           if ( targetMesh != myMesh )
11677           {
11678             // add 1D elements on face boundary to be added to a new mesh
11679             const SMDS_MeshElement* edge;
11680             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11681             {
11682               if ( iQuad )
11683                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11684               else
11685                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11686               if ( edge && avoidSet.insert( edge ).second )
11687                 presentBndElems.push_back( edge );
11688             }
11689           }
11690         }
11691       }
11692     }
11693     else                     // elem is a face ------------------------------------------
11694     {
11695       avoidSet.clear(), avoidSet.insert( elem );
11696       int nbNodes = elem->NbCornerNodes();
11697       nodes.resize( 2 /*+ iQuad*/);
11698       for ( int i = 0; i < nbNodes; i++ )
11699       {
11700         nodes[0] = elem->GetNode(i);
11701         nodes[1] = elem->GetNode((i+1)%nbNodes);
11702         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11703           continue; // not free link
11704
11705         //if ( iQuad )
11706         //nodes[2] = elem->GetNode( i + nbNodes );
11707         if ( const SMDS_MeshElement* edge =
11708              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11709           presentBndElems.push_back( edge );
11710         else
11711           missingBndElems.push_back( nodes );
11712       }
11713     }
11714
11715     // ---------------------------------
11716     // 2. Add missing boundary elements
11717     // ---------------------------------
11718     if ( targetMesh != myMesh )
11719       // instead of making a map of nodes in this mesh and targetMesh,
11720       // we create nodes with same IDs.
11721       for ( int i = 0; i < missingBndElems.size(); ++i )
11722       {
11723         TConnectivity& srcNodes = missingBndElems[i];
11724         TConnectivity  nodes( srcNodes.size() );
11725         for ( inode = 0; inode < nodes.size(); ++inode )
11726           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11727         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11728                                                                    missType,
11729                                                                    /*noMedium=*/true))
11730           continue;
11731         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11732         ++nbAddedBnd;
11733       }
11734     else
11735       for ( int i = 0; i < missingBndElems.size(); ++i )
11736       {
11737         TConnectivity& nodes = missingBndElems[i];
11738         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11739                                                                    missType,
11740                                                                    /*noMedium=*/true))
11741           continue;
11742         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11743         ++nbAddedBnd;
11744       }
11745
11746     // ----------------------------------
11747     // 3. Copy present boundary elements
11748     // ----------------------------------
11749     if ( toCopyExistingBoundary )
11750       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11751       {
11752         const SMDS_MeshElement* e = presentBndElems[i];
11753         TConnectivity nodes( e->NbNodes() );
11754         for ( inode = 0; inode < nodes.size(); ++inode )
11755           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11756         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11757       }
11758     else // store present elements to add them to a group
11759       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11760       {
11761         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11762       }
11763       
11764   } // loop on given elements
11765
11766   // ---------------------------------------------
11767   // 4. Fill group with boundary elements
11768   // ---------------------------------------------
11769   if ( group )
11770   {
11771     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11772       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11773         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11774   }
11775   tgtEditor.myLastCreatedElems.Clear();
11776   tgtEditor2.myLastCreatedElems.Clear();
11777
11778   // -----------------------
11779   // 5. Copy given elements
11780   // -----------------------
11781   if ( toCopyElements && targetMesh != myMesh )
11782   {
11783     if (elements.empty())
11784       eIt = aMesh->elementsIterator(elemType);
11785     else
11786       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11787     while (eIt->more())
11788     {
11789       const SMDS_MeshElement* elem = eIt->next();
11790       TConnectivity nodes( elem->NbNodes() );
11791       for ( inode = 0; inode < nodes.size(); ++inode )
11792         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11793       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11794
11795       tgtEditor.myLastCreatedElems.Clear();
11796     }
11797   }
11798   return nbAddedBnd;
11799 }