Salome HOME
8bb6d8c780f4b356d00d32d03ae9ed1523d6a666
[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 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
23 // File      : SMESH_MeshEditor.cxx
24 // Created   : Mon Apr 12 16:10:22 2004
25 // Author    : Edward AGAPOV (eap)
26
27 #define CHRONODEF
28 #include "SMESH_MeshEditor.hxx"
29
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_SpacePosition.hxx"
36 //#include "SMDS_QuadraticFaceOfNodes.hxx"
37 #include "SMDS_MeshGroup.hxx"
38 #include "SMDS_LinearEdge.hxx"
39 #include "SMDS_Downward.hxx"
40 #include "SMDS_SetIterator.hxx"
41
42 #include "SMESHDS_Group.hxx"
43 #include "SMESHDS_Mesh.hxx"
44
45 #include "SMESH_Algo.hxx"
46 #include "SMESH_ControlsDef.hxx"
47 #include "SMESH_Group.hxx"
48 #include "SMESH_MesherHelper.hxx"
49 #include "SMESH_OctreeNode.hxx"
50 #include "SMESH_subMesh.hxx"
51
52 #include <Basics_OCCTVersion.hxx>
53
54 #include "utilities.h"
55
56 #include <BRepAdaptor_Surface.hxx>
57 #include <BRepClass3d_SolidClassifier.hxx>
58 #include <BRep_Tool.hxx>
59 #include <ElCLib.hxx>
60 #include <Extrema_GenExtPS.hxx>
61 #include <Extrema_POnCurv.hxx>
62 #include <Extrema_POnSurf.hxx>
63 #include <GC_MakeSegment.hxx>
64 #include <Geom2d_Curve.hxx>
65 #include <GeomAPI_ExtremaCurveCurve.hxx>
66 #include <GeomAdaptor_Surface.hxx>
67 #include <Geom_Curve.hxx>
68 #include <Geom_Line.hxx>
69 #include <Geom_Surface.hxx>
70 #include <IntAna_IntConicQuad.hxx>
71 #include <IntAna_Quadric.hxx>
72 #include <Precision.hxx>
73 #include <TColStd_ListOfInteger.hxx>
74 #include <TopAbs_State.hxx>
75 #include <TopExp.hxx>
76 #include <TopExp_Explorer.hxx>
77 #include <TopTools_ListIteratorOfListOfShape.hxx>
78 #include <TopTools_ListOfShape.hxx>
79 #include <TopTools_SequenceOfShape.hxx>
80 #include <TopoDS.hxx>
81 #include <TopoDS_Face.hxx>
82 #include <gp.hxx>
83 #include <gp_Ax1.hxx>
84 #include <gp_Dir.hxx>
85 #include <gp_Lin.hxx>
86 #include <gp_Pln.hxx>
87 #include <gp_Trsf.hxx>
88 #include <gp_Vec.hxx>
89 #include <gp_XY.hxx>
90 #include <gp_XYZ.hxx>
91
92 #include <math.h>
93
94 #include <map>
95 #include <set>
96 #include <numeric>
97 #include <limits>
98 #include <algorithm>
99 #include <sstream>
100
101 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
102
103 using namespace std;
104 using namespace SMESH::Controls;
105
106 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
107 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
108
109 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
110
111 //=======================================================================
112 //function : SMESH_MeshEditor
113 //purpose  :
114 //=======================================================================
115
116 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
117   :myMesh( theMesh ) // theMesh may be NULL
118 {
119 }
120
121 //=======================================================================
122 /*!
123  * \brief Add element
124  */
125 //=======================================================================
126
127 SMDS_MeshElement*
128 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
129                              const SMDSAbs_ElementType            type,
130                              const bool                           isPoly,
131                              const int                            ID)
132 {
133   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
134   SMDS_MeshElement* e = 0;
135   int nbnode = node.size();
136   SMESHDS_Mesh* mesh = GetMeshDS();
137   switch ( type ) {
138   case SMDSAbs_Face:
139     if ( !isPoly ) {
140       if      (nbnode == 3) {
141         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
142         else           e = mesh->AddFace      (node[0], node[1], node[2] );
143       }
144       else if (nbnode == 4) {
145         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
146         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
147       }
148       else if (nbnode == 6) {
149         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
150                                                node[4], node[5], ID);
151         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
152                                                node[4], node[5] );
153       }
154       else if (nbnode == 8) {
155         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
156                                                node[4], node[5], node[6], node[7], ID);
157         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
158                                                node[4], node[5], node[6], node[7] );
159       }
160     } else {
161       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
162       else           e = mesh->AddPolygonalFace      (node    );
163     }
164     break;
165
166   case SMDSAbs_Volume:
167     if ( !isPoly ) {
168       if      (nbnode == 4) {
169         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
170         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
171       }
172       else if (nbnode == 5) {
173         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
174                                                  node[4], ID);
175         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
176                                                  node[4] );
177       }
178       else if (nbnode == 6) {
179         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
180                                                  node[4], node[5], ID);
181         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
182                                                  node[4], node[5] );
183       }
184       else if (nbnode == 8) {
185         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
186                                                  node[4], node[5], node[6], node[7], ID);
187         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
188                                                  node[4], node[5], node[6], node[7] );
189       }
190       else if (nbnode == 10) {
191         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
192                                                  node[4], node[5], node[6], node[7],
193                                                  node[8], node[9], ID);
194         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
195                                                  node[4], node[5], node[6], node[7],
196                                                  node[8], node[9] );
197       }
198       else if (nbnode == 13) {
199         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
200                                                  node[4], node[5], node[6], node[7],
201                                                  node[8], node[9], node[10],node[11],
202                                                  node[12],ID);
203         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
204                                                  node[4], node[5], node[6], node[7],
205                                                  node[8], node[9], node[10],node[11],
206                                                  node[12] );
207       }
208       else if (nbnode == 15) {
209         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
210                                                  node[4], node[5], node[6], node[7],
211                                                  node[8], node[9], node[10],node[11],
212                                                  node[12],node[13],node[14],ID);
213         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
214                                                  node[4], node[5], node[6], node[7],
215                                                  node[8], node[9], node[10],node[11],
216                                                  node[12],node[13],node[14] );
217       }
218       else if (nbnode == 20) {
219         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
220                                                  node[4], node[5], node[6], node[7],
221                                                  node[8], node[9], node[10],node[11],
222                                                  node[12],node[13],node[14],node[15],
223                                                  node[16],node[17],node[18],node[19],ID);
224         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
225                                                  node[4], node[5], node[6], node[7],
226                                                  node[8], node[9], node[10],node[11],
227                                                  node[12],node[13],node[14],node[15],
228                                                  node[16],node[17],node[18],node[19] );
229       }
230     }
231     break;
232
233   case SMDSAbs_Edge:
234     if ( nbnode == 2 ) {
235       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
236       else           e = mesh->AddEdge      (node[0], node[1] );
237     }
238     else if ( nbnode == 3 ) {
239       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
240       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
241     }
242     break;
243
244   case SMDSAbs_0DElement:
245     if ( nbnode == 1 ) {
246       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
247       else           e = mesh->Add0DElement      (node[0] );
248     }
249     break;
250
251   case SMDSAbs_Node:
252     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
253     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
254     break;
255
256   default:;
257   }
258   if ( e ) myLastCreatedElems.Append( e );
259   return e;
260 }
261
262 //=======================================================================
263 /*!
264  * \brief Add element
265  */
266 //=======================================================================
267
268 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
269                                                const SMDSAbs_ElementType type,
270                                                const bool                isPoly,
271                                                const int                 ID)
272 {
273   vector<const SMDS_MeshNode*> nodes;
274   nodes.reserve( nodeIDs.size() );
275   vector<int>::const_iterator id = nodeIDs.begin();
276   while ( id != nodeIDs.end() ) {
277     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
278       nodes.push_back( node );
279     else
280       return 0;
281   }
282   return AddElement( nodes, type, isPoly, ID );
283 }
284
285 //=======================================================================
286 //function : Remove
287 //purpose  : Remove a node or an element.
288 //           Modify a compute state of sub-meshes which become empty
289 //=======================================================================
290
291 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
292                               const bool         isNodes )
293 {
294   myLastCreatedElems.Clear();
295   myLastCreatedNodes.Clear();
296
297   SMESHDS_Mesh* aMesh = GetMeshDS();
298   set< SMESH_subMesh *> smmap;
299
300   int removed = 0;
301   list<int>::const_iterator it = theIDs.begin();
302   for ( ; it != theIDs.end(); it++ ) {
303     const SMDS_MeshElement * elem;
304     if ( isNodes )
305       elem = aMesh->FindNode( *it );
306     else
307       elem = aMesh->FindElement( *it );
308     if ( !elem )
309       continue;
310
311     // Notify VERTEX sub-meshes about modification
312     if ( isNodes ) {
313       const SMDS_MeshNode* node = cast2Node( elem );
314       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
315         if ( int aShapeID = node->getshapeId() )
316           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
317             smmap.insert( sm );
318     }
319     // Find sub-meshes to notify about modification
320     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
321     //     while ( nodeIt->more() ) {
322     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
323     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
324     //       if ( aPosition.get() ) {
325     //         if ( int aShapeID = aPosition->GetShapeId() ) {
326     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
327     //             smmap.insert( sm );
328     //         }
329     //       }
330     //     }
331
332     // Do remove
333     if ( isNodes )
334       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
335     else
336       aMesh->RemoveElement( elem );
337     removed++;
338   }
339
340   // Notify sub-meshes about modification
341   if ( !smmap.empty() ) {
342     set< SMESH_subMesh *>::iterator smIt;
343     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
344       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
345   }
346
347   //   // Check if the whole mesh becomes empty
348   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
349   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
350
351   return removed;
352 }
353
354 //=======================================================================
355 //function : FindShape
356 //purpose  : Return an index of the shape theElem is on
357 //           or zero if a shape not found
358 //=======================================================================
359
360 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
361 {
362   myLastCreatedElems.Clear();
363   myLastCreatedNodes.Clear();
364
365   SMESHDS_Mesh * aMesh = GetMeshDS();
366   if ( aMesh->ShapeToMesh().IsNull() )
367     return 0;
368
369   int aShapeID = theElem->getshapeId();
370   if ( aShapeID < 1 )
371     return 0;
372
373   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
374     if ( sm->Contains( theElem ))
375       return aShapeID;
376
377   if ( theElem->GetType() == SMDSAbs_Node ) {
378     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
379   }
380   else {
381     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
382   }
383
384   TopoDS_Shape aShape; // the shape a node of theElem is on
385   if ( theElem->GetType() != SMDSAbs_Node )
386   {
387     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
388     while ( nodeIt->more() ) {
389       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
390       if ((aShapeID = node->getshapeId()) > 0) {
391         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
392           if ( sm->Contains( theElem ))
393             return aShapeID;
394           if ( aShape.IsNull() )
395             aShape = aMesh->IndexToShape( aShapeID );
396         }
397       }
398     }
399   }
400
401   // None of nodes is on a proper shape,
402   // find the shape among ancestors of aShape on which a node is
403   if ( !aShape.IsNull() ) {
404     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
405     for ( ; ancIt.More(); ancIt.Next() ) {
406       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
407       if ( sm && sm->Contains( theElem ))
408         return aMesh->ShapeToIndex( ancIt.Value() );
409     }
410   }
411   else
412   {
413     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
414     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
415     for ( ; id_sm != id2sm.end(); ++id_sm )
416       if ( id_sm->second->Contains( theElem ))
417         return id_sm->first;
418   }
419
420   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
421   return 0;
422 }
423
424 //=======================================================================
425 //function : IsMedium
426 //purpose  :
427 //=======================================================================
428
429 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
430                                 const SMDSAbs_ElementType typeToCheck)
431 {
432   bool isMedium = false;
433   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
434   while (it->more() && !isMedium ) {
435     const SMDS_MeshElement* elem = it->next();
436     isMedium = elem->IsMediumNode(node);
437   }
438   return isMedium;
439 }
440
441 //=======================================================================
442 //function : ShiftNodesQuadTria
443 //purpose  : auxilary
444 //           Shift nodes in the array corresponded to quadratic triangle
445 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
446 //=======================================================================
447 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
448 {
449   const SMDS_MeshNode* nd1 = aNodes[0];
450   aNodes[0] = aNodes[1];
451   aNodes[1] = aNodes[2];
452   aNodes[2] = nd1;
453   const SMDS_MeshNode* nd2 = aNodes[3];
454   aNodes[3] = aNodes[4];
455   aNodes[4] = aNodes[5];
456   aNodes[5] = nd2;
457 }
458
459 //=======================================================================
460 //function : GetNodesFromTwoTria
461 //purpose  : auxilary
462 //           Shift nodes in the array corresponded to quadratic triangle
463 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
464 //=======================================================================
465 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
466                                 const SMDS_MeshElement * theTria2,
467                                 const SMDS_MeshNode* N1[],
468                                 const SMDS_MeshNode* N2[])
469 {
470   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
471   int i=0;
472   while(i<6) {
473     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
474     i++;
475   }
476   if(it->more()) return false;
477   it = theTria2->nodesIterator();
478   i=0;
479   while(i<6) {
480     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
481     i++;
482   }
483   if(it->more()) return false;
484
485   int sames[3] = {-1,-1,-1};
486   int nbsames = 0;
487   int j;
488   for(i=0; i<3; i++) {
489     for(j=0; j<3; j++) {
490       if(N1[i]==N2[j]) {
491         sames[i] = j;
492         nbsames++;
493         break;
494       }
495     }
496   }
497   if(nbsames!=2) return false;
498   if(sames[0]>-1) {
499     ShiftNodesQuadTria(N1);
500     if(sames[1]>-1) {
501       ShiftNodesQuadTria(N1);
502     }
503   }
504   i = sames[0] + sames[1] + sames[2];
505   for(; i<2; i++) {
506     ShiftNodesQuadTria(N2);
507   }
508   // now we receive following N1 and N2 (using numeration as above image)
509   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
510   // i.e. first nodes from both arrays determ new diagonal
511   return true;
512 }
513
514 //=======================================================================
515 //function : InverseDiag
516 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
517 //           but having other common link.
518 //           Return False if args are improper
519 //=======================================================================
520
521 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
522                                     const SMDS_MeshElement * theTria2 )
523 {
524   MESSAGE("InverseDiag");
525   myLastCreatedElems.Clear();
526   myLastCreatedNodes.Clear();
527
528   if (!theTria1 || !theTria2)
529     return false;
530
531   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
532   if (!F1) return false;
533   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
534   if (!F2) return false;
535   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
536       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
537
538     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
539     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
540     //    |/ |                                         | \|
541     //  B +--+ 2                                     B +--+ 2
542
543     // put nodes in array and find out indices of the same ones
544     const SMDS_MeshNode* aNodes [6];
545     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
546     int i = 0;
547     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
548     while ( it->more() ) {
549       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
550
551       if ( i > 2 ) // theTria2
552         // find same node of theTria1
553         for ( int j = 0; j < 3; j++ )
554           if ( aNodes[ i ] == aNodes[ j ]) {
555             sameInd[ j ] = i;
556             sameInd[ i ] = j;
557             break;
558           }
559       // next
560       i++;
561       if ( i == 3 ) {
562         if ( it->more() )
563           return false; // theTria1 is not a triangle
564         it = theTria2->nodesIterator();
565       }
566       if ( i == 6 && it->more() )
567         return false; // theTria2 is not a triangle
568     }
569
570     // find indices of 1,2 and of A,B in theTria1
571     int iA = 0, iB = 0, i1 = 0, i2 = 0;
572     for ( i = 0; i < 6; i++ ) {
573       if ( sameInd [ i ] == 0 ) {
574         if ( i < 3 ) i1 = i;
575         else         i2 = i;
576       }
577       else if (i < 3) {
578         if ( iA ) iB = i;
579         else      iA = i;
580       }
581     }
582     // nodes 1 and 2 should not be the same
583     if ( aNodes[ i1 ] == aNodes[ i2 ] )
584       return false;
585
586     // theTria1: A->2
587     aNodes[ iA ] = aNodes[ i2 ];
588     // theTria2: B->1
589     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
590
591     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
592     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
593
594     return true;
595
596   } // end if(F1 && F2)
597
598   // check case of quadratic faces
599   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
600     return false;
601   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
602     return false;
603
604   //       5
605   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
606   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
607   //    |   / |
608   //  7 +  +  + 6
609   //    | /9  |
610   //    |/    |
611   //  4 +--+--+ 3
612   //       8
613
614   const SMDS_MeshNode* N1 [6];
615   const SMDS_MeshNode* N2 [6];
616   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
617     return false;
618   // now we receive following N1 and N2 (using numeration as above image)
619   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
620   // i.e. first nodes from both arrays determ new diagonal
621
622   const SMDS_MeshNode* N1new [6];
623   const SMDS_MeshNode* N2new [6];
624   N1new[0] = N1[0];
625   N1new[1] = N2[0];
626   N1new[2] = N2[1];
627   N1new[3] = N1[4];
628   N1new[4] = N2[3];
629   N1new[5] = N1[5];
630   N2new[0] = N1[0];
631   N2new[1] = N1[1];
632   N2new[2] = N2[0];
633   N2new[3] = N1[3];
634   N2new[4] = N2[5];
635   N2new[5] = N1[4];
636   // replaces nodes in faces
637   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
638   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
639
640   return true;
641 }
642
643 //=======================================================================
644 //function : findTriangles
645 //purpose  : find triangles sharing theNode1-theNode2 link
646 //=======================================================================
647
648 static bool findTriangles(const SMDS_MeshNode *    theNode1,
649                           const SMDS_MeshNode *    theNode2,
650                           const SMDS_MeshElement*& theTria1,
651                           const SMDS_MeshElement*& theTria2)
652 {
653   if ( !theNode1 || !theNode2 ) return false;
654
655   theTria1 = theTria2 = 0;
656
657   set< const SMDS_MeshElement* > emap;
658   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
659   while (it->more()) {
660     const SMDS_MeshElement* elem = it->next();
661     if ( elem->NbNodes() == 3 )
662       emap.insert( elem );
663   }
664   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
665   while (it->more()) {
666     const SMDS_MeshElement* elem = it->next();
667     if ( emap.find( elem ) != emap.end() ) {
668       if ( theTria1 ) {
669         // theTria1 must be element with minimum ID
670         if( theTria1->GetID() < elem->GetID() ) {
671           theTria2 = elem;
672         }
673         else {
674           theTria2 = theTria1;
675           theTria1 = elem;
676         }
677         break;
678       }
679       else {
680         theTria1 = elem;
681       }
682     }
683   }
684   return ( theTria1 && theTria2 );
685 }
686
687 //=======================================================================
688 //function : InverseDiag
689 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
690 //           with ones built on the same 4 nodes but having other common link.
691 //           Return false if proper faces not found
692 //=======================================================================
693
694 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
695                                     const SMDS_MeshNode * theNode2)
696 {
697   myLastCreatedElems.Clear();
698   myLastCreatedNodes.Clear();
699
700   MESSAGE( "::InverseDiag()" );
701
702   const SMDS_MeshElement *tr1, *tr2;
703   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
704     return false;
705
706   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
707   if (!F1) return false;
708   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
709   if (!F2) return false;
710   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
711       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
712
713     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
714     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
715     //    |/ |                                    | \|
716     //  B +--+ 2                                B +--+ 2
717
718     // put nodes in array
719     // and find indices of 1,2 and of A in tr1 and of B in tr2
720     int i, iA1 = 0, i1 = 0;
721     const SMDS_MeshNode* aNodes1 [3];
722     SMDS_ElemIteratorPtr it;
723     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
724       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
725       if ( aNodes1[ i ] == theNode1 )
726         iA1 = i; // node A in tr1
727       else if ( aNodes1[ i ] != theNode2 )
728         i1 = i;  // node 1
729     }
730     int iB2 = 0, i2 = 0;
731     const SMDS_MeshNode* aNodes2 [3];
732     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
733       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
734       if ( aNodes2[ i ] == theNode2 )
735         iB2 = i; // node B in tr2
736       else if ( aNodes2[ i ] != theNode1 )
737         i2 = i;  // node 2
738     }
739
740     // nodes 1 and 2 should not be the same
741     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
742       return false;
743
744     // tr1: A->2
745     aNodes1[ iA1 ] = aNodes2[ i2 ];
746     // tr2: B->1
747     aNodes2[ iB2 ] = aNodes1[ i1 ];
748
749     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
750     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
751
752     return true;
753   }
754
755   // check case of quadratic faces
756   return InverseDiag(tr1,tr2);
757 }
758
759 //=======================================================================
760 //function : getQuadrangleNodes
761 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
762 //           fusion of triangles tr1 and tr2 having shared link on
763 //           theNode1 and theNode2
764 //=======================================================================
765
766 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
767                         const SMDS_MeshNode *    theNode1,
768                         const SMDS_MeshNode *    theNode2,
769                         const SMDS_MeshElement * tr1,
770                         const SMDS_MeshElement * tr2 )
771 {
772   if( tr1->NbNodes() != tr2->NbNodes() )
773     return false;
774   // find the 4-th node to insert into tr1
775   const SMDS_MeshNode* n4 = 0;
776   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
777   int i=0;
778   while ( !n4 && i<3 ) {
779     const SMDS_MeshNode * n = cast2Node( it->next() );
780     i++;
781     bool isDiag = ( n == theNode1 || n == theNode2 );
782     if ( !isDiag )
783       n4 = n;
784   }
785   // Make an array of nodes to be in a quadrangle
786   int iNode = 0, iFirstDiag = -1;
787   it = tr1->nodesIterator();
788   i=0;
789   while ( i<3 ) {
790     const SMDS_MeshNode * n = cast2Node( it->next() );
791     i++;
792     bool isDiag = ( n == theNode1 || n == theNode2 );
793     if ( isDiag ) {
794       if ( iFirstDiag < 0 )
795         iFirstDiag = iNode;
796       else if ( iNode - iFirstDiag == 1 )
797         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
798     }
799     else if ( n == n4 ) {
800       return false; // tr1 and tr2 should not have all the same nodes
801     }
802     theQuadNodes[ iNode++ ] = n;
803   }
804   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
805     theQuadNodes[ iNode ] = n4;
806
807   return true;
808 }
809
810 //=======================================================================
811 //function : DeleteDiag
812 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
813 //           with a quadrangle built on the same 4 nodes.
814 //           Return false if proper faces not found
815 //=======================================================================
816
817 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
818                                    const SMDS_MeshNode * theNode2)
819 {
820   myLastCreatedElems.Clear();
821   myLastCreatedNodes.Clear();
822
823   MESSAGE( "::DeleteDiag()" );
824
825   const SMDS_MeshElement *tr1, *tr2;
826   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
827     return false;
828
829   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
830   if (!F1) return false;
831   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
832   if (!F2) return false;
833   SMESHDS_Mesh * aMesh = GetMeshDS();
834
835   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
836       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
837
838     const SMDS_MeshNode* aNodes [ 4 ];
839     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
840       return false;
841
842     const SMDS_MeshElement* newElem = 0;
843     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
844     myLastCreatedElems.Append(newElem);
845     AddToSameGroups( newElem, tr1, aMesh );
846     int aShapeId = tr1->getshapeId();
847     if ( aShapeId )
848       {
849         aMesh->SetMeshElementOnShape( newElem, aShapeId );
850       }
851     aMesh->RemoveElement( tr1 );
852     aMesh->RemoveElement( tr2 );
853
854     return true;
855   }
856
857   // check case of quadratic faces
858   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
859     return false;
860   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
861     return false;
862
863   //       5
864   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
865   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
866   //    |   / |
867   //  7 +  +  + 6
868   //    | /9  |
869   //    |/    |
870   //  4 +--+--+ 3
871   //       8
872
873   const SMDS_MeshNode* N1 [6];
874   const SMDS_MeshNode* N2 [6];
875   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
876     return false;
877   // now we receive following N1 and N2 (using numeration as above image)
878   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
879   // i.e. first nodes from both arrays determ new diagonal
880
881   const SMDS_MeshNode* aNodes[8];
882   aNodes[0] = N1[0];
883   aNodes[1] = N1[1];
884   aNodes[2] = N2[0];
885   aNodes[3] = N2[1];
886   aNodes[4] = N1[3];
887   aNodes[5] = N2[5];
888   aNodes[6] = N2[3];
889   aNodes[7] = N1[5];
890
891   const SMDS_MeshElement* newElem = 0;
892   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
893                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
894   myLastCreatedElems.Append(newElem);
895   AddToSameGroups( newElem, tr1, aMesh );
896   int aShapeId = tr1->getshapeId();
897   if ( aShapeId )
898     {
899       aMesh->SetMeshElementOnShape( newElem, aShapeId );
900     }
901   aMesh->RemoveElement( tr1 );
902   aMesh->RemoveElement( tr2 );
903
904   // remove middle node (9)
905   GetMeshDS()->RemoveNode( N1[4] );
906
907   return true;
908 }
909
910 //=======================================================================
911 //function : Reorient
912 //purpose  : Reverse theElement orientation
913 //=======================================================================
914
915 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
916 {
917   MESSAGE("Reorient");
918   myLastCreatedElems.Clear();
919   myLastCreatedNodes.Clear();
920
921   if (!theElem)
922     return false;
923   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
924   if ( !it || !it->more() )
925     return false;
926
927   switch ( theElem->GetType() ) {
928
929   case SMDSAbs_Edge:
930   case SMDSAbs_Face: {
931     if(!theElem->IsQuadratic()) {
932       int i = theElem->NbNodes();
933       vector<const SMDS_MeshNode*> aNodes( i );
934       while ( it->more() )
935         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
936       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
937     }
938     else {
939       // quadratic elements
940       if(theElem->GetType()==SMDSAbs_Edge) {
941         vector<const SMDS_MeshNode*> aNodes(3);
942         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
943         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
944         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
945         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
946       }
947       else {
948         int nbn = theElem->NbNodes();
949         vector<const SMDS_MeshNode*> aNodes(nbn);
950         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
951         int i=1;
952         for(; i<nbn/2; i++) {
953           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
954         }
955         for(i=0; i<nbn/2; i++) {
956           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
957         }
958         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
959       }
960     }
961   }
962   case SMDSAbs_Volume: {
963     if (theElem->IsPoly()) {
964       // TODO reorient vtk polyhedron
965       MESSAGE("reorient vtk polyhedron ?");
966       const SMDS_VtkVolume* aPolyedre =
967         dynamic_cast<const SMDS_VtkVolume*>( theElem );
968       if (!aPolyedre) {
969         MESSAGE("Warning: bad volumic element");
970         return false;
971       }
972
973       int nbFaces = aPolyedre->NbFaces();
974       vector<const SMDS_MeshNode *> poly_nodes;
975       vector<int> quantities (nbFaces);
976
977       // reverse each face of the polyedre
978       for (int iface = 1; iface <= nbFaces; iface++) {
979         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
980         quantities[iface - 1] = nbFaceNodes;
981
982         for (inode = nbFaceNodes; inode >= 1; inode--) {
983           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
984           poly_nodes.push_back(curNode);
985         }
986       }
987
988       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
989
990     }
991     else {
992       SMDS_VolumeTool vTool;
993       if ( !vTool.Set( theElem ))
994         return false;
995       vTool.Inverse();
996       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
997       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
998     }
999   }
1000   default:;
1001   }
1002
1003   return false;
1004 }
1005
1006 //=======================================================================
1007 //function : getBadRate
1008 //purpose  :
1009 //=======================================================================
1010
1011 static double getBadRate (const SMDS_MeshElement*               theElem,
1012                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1013 {
1014   SMESH::Controls::TSequenceOfXYZ P;
1015   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1016     return 1e100;
1017   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1018   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1019 }
1020
1021 //=======================================================================
1022 //function : QuadToTri
1023 //purpose  : Cut quadrangles into triangles.
1024 //           theCrit is used to select a diagonal to cut
1025 //=======================================================================
1026
1027 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1028                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1029 {
1030   myLastCreatedElems.Clear();
1031   myLastCreatedNodes.Clear();
1032
1033   MESSAGE( "::QuadToTri()" );
1034
1035   if ( !theCrit.get() )
1036     return false;
1037
1038   SMESHDS_Mesh * aMesh = GetMeshDS();
1039
1040   Handle(Geom_Surface) surface;
1041   SMESH_MesherHelper   helper( *GetMesh() );
1042
1043   TIDSortedElemSet::iterator itElem;
1044   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1045     const SMDS_MeshElement* elem = *itElem;
1046     if ( !elem || elem->GetType() != SMDSAbs_Face )
1047       continue;
1048     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1049       continue;
1050
1051     // retrieve element nodes
1052     const SMDS_MeshNode* aNodes [8];
1053     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1054     int i = 0;
1055     while ( itN->more() )
1056       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1057
1058     // compare two sets of possible triangles
1059     double aBadRate1, aBadRate2; // to what extent a set is bad
1060     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1061     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1062     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1063
1064     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1065     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1066     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1067
1068     int aShapeId = FindShape( elem );
1069     const SMDS_MeshElement* newElem1 = 0;
1070     const SMDS_MeshElement* newElem2 = 0;
1071
1072     if( !elem->IsQuadratic() ) {
1073
1074       // split liner quadrangle
1075       if ( aBadRate1 <= aBadRate2 ) {
1076         // tr1 + tr2 is better
1077         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1078         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1079       }
1080       else {
1081         // tr3 + tr4 is better
1082         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1083         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1084       }
1085     }
1086     else {
1087
1088       // split quadratic quadrangle
1089
1090       // get surface elem is on
1091       if ( aShapeId != helper.GetSubShapeID() ) {
1092         surface.Nullify();
1093         TopoDS_Shape shape;
1094         if ( aShapeId > 0 )
1095           shape = aMesh->IndexToShape( aShapeId );
1096         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1097           TopoDS_Face face = TopoDS::Face( shape );
1098           surface = BRep_Tool::Surface( face );
1099           if ( !surface.IsNull() )
1100             helper.SetSubShape( shape );
1101         }
1102       }
1103       // get elem nodes
1104       const SMDS_MeshNode* aNodes [8];
1105       const SMDS_MeshNode* inFaceNode = 0;
1106       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1107       int i = 0;
1108       while ( itN->more() ) {
1109         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1110         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1111              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1112         {
1113           inFaceNode = aNodes[ i-1 ];
1114         }
1115       }
1116       // find middle point for (0,1,2,3)
1117       // and create a node in this point;
1118       gp_XYZ p( 0,0,0 );
1119       if ( surface.IsNull() ) {
1120         for(i=0; i<4; i++)
1121           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1122         p /= 4;
1123       }
1124       else {
1125         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1126         gp_XY uv( 0,0 );
1127         for(i=0; i<4; i++)
1128           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1129         uv /= 4.;
1130         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1131       }
1132       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1133       myLastCreatedNodes.Append(newN);
1134
1135       // create a new element
1136       if ( aBadRate1 <= aBadRate2 ) {
1137         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1138                                   aNodes[6], aNodes[7], newN );
1139         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1140                                   newN,      aNodes[4], aNodes[5] );
1141       }
1142       else {
1143         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1144                                   aNodes[7], aNodes[4], newN );
1145         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1146                                   newN,      aNodes[5], aNodes[6] );
1147       }
1148     } // quadratic case
1149
1150     // care of a new element
1151
1152     myLastCreatedElems.Append(newElem1);
1153     myLastCreatedElems.Append(newElem2);
1154     AddToSameGroups( newElem1, elem, aMesh );
1155     AddToSameGroups( newElem2, elem, aMesh );
1156
1157     // put a new triangle on the same shape
1158     if ( aShapeId )
1159       {
1160         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1161         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1162       }
1163     aMesh->RemoveElement( elem );
1164   }
1165   return true;
1166 }
1167
1168 //=======================================================================
1169 //function : BestSplit
1170 //purpose  : Find better diagonal for cutting.
1171 //=======================================================================
1172
1173 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1174                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1175 {
1176   myLastCreatedElems.Clear();
1177   myLastCreatedNodes.Clear();
1178
1179   if (!theCrit.get())
1180     return -1;
1181
1182   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1183     return -1;
1184
1185   if( theQuad->NbNodes()==4 ||
1186       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1187
1188     // retrieve element nodes
1189     const SMDS_MeshNode* aNodes [4];
1190     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1191     int i = 0;
1192     //while (itN->more())
1193     while (i<4) {
1194       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1195     }
1196     // compare two sets of possible triangles
1197     double aBadRate1, aBadRate2; // to what extent a set is bad
1198     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1199     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1200     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1201
1202     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1203     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1204     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1205
1206     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1207       return 1; // diagonal 1-3
1208
1209     return 2; // diagonal 2-4
1210   }
1211   return -1;
1212 }
1213
1214 namespace
1215 {
1216   // Methods of splitting volumes into tetra
1217
1218   const int theHexTo5_1[5*4+1] =
1219     {
1220       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1221     };
1222   const int theHexTo5_2[5*4+1] =
1223     {
1224       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1225     };
1226   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1227
1228   const int theHexTo6_1[6*4+1] =
1229     {
1230       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
1231     };
1232   const int theHexTo6_2[6*4+1] =
1233     {
1234       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
1235     };
1236   const int theHexTo6_3[6*4+1] =
1237     {
1238       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
1239     };
1240   const int theHexTo6_4[6*4+1] =
1241     {
1242       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
1243     };
1244   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1245
1246   const int thePyraTo2_1[2*4+1] =
1247     {
1248       0, 1, 2, 4,    0, 2, 3, 4,   -1
1249     };
1250   const int thePyraTo2_2[2*4+1] =
1251     {
1252       1, 2, 3, 4,    1, 3, 0, 4,   -1
1253     };
1254   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1255
1256   const int thePentaTo3_1[3*4+1] =
1257     {
1258       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1259     };
1260   const int thePentaTo3_2[3*4+1] =
1261     {
1262       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1263     };
1264   const int thePentaTo3_3[3*4+1] =
1265     {
1266       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1267     };
1268   const int thePentaTo3_4[3*4+1] =
1269     {
1270       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1271     };
1272   const int thePentaTo3_5[3*4+1] =
1273     {
1274       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1275     };
1276   const int thePentaTo3_6[3*4+1] =
1277     {
1278       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1279     };
1280   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1281                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1282
1283   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1284   {
1285     int _n1, _n2, _n3;
1286     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1287     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1288     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1289   };
1290   struct TSplitMethod
1291   {
1292     int        _nbTetra;
1293     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1294     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1295     bool       _ownConn;      //!< to delete _connectivity in destructor
1296     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1297
1298     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1299       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1300     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1301     bool hasFacet( const TTriangleFacet& facet ) const
1302     {
1303       const int* tetConn = _connectivity;
1304       for ( ; tetConn[0] >= 0; tetConn += 4 )
1305         if (( facet.contains( tetConn[0] ) +
1306               facet.contains( tetConn[1] ) +
1307               facet.contains( tetConn[2] ) +
1308               facet.contains( tetConn[3] )) == 3 )
1309           return true;
1310       return false;
1311     }
1312   };
1313
1314   //=======================================================================
1315   /*!
1316    * \brief return TSplitMethod for the given element
1317    */
1318   //=======================================================================
1319
1320   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1321   {
1322     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1323
1324     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1325     // an edge and a face barycenter; tertaherdons are based on triangles and
1326     // a volume barycenter
1327     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1328
1329     // Find out how adjacent volumes are split
1330
1331     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1332     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1333     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1334     {
1335       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1336       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1337       if ( nbNodes < 4 ) continue;
1338
1339       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1340       const int* nInd = vol.GetFaceNodesIndices( iF );
1341       if ( nbNodes == 4 )
1342       {
1343         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1344         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1345         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1346         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1347       }
1348       else
1349       {
1350         int iCom = 0; // common node of triangle faces to split into
1351         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1352         {
1353           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1354                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1355                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1356           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1357                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1358                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1359           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1360           {
1361             triaSplits.push_back( t012 );
1362             triaSplits.push_back( t023 );
1363             break;
1364           }
1365         }
1366       }
1367       if ( !triaSplits.empty() )
1368         hasAdjacentSplits = true;
1369     }
1370
1371     // Among variants of split method select one compliant with adjacent volumes
1372
1373     TSplitMethod method;
1374     if ( !vol.Element()->IsPoly() && !is24TetMode )
1375     {
1376       int nbVariants = 2, nbTet = 0;
1377       const int** connVariants = 0;
1378       switch ( vol.Element()->GetEntityType() )
1379       {
1380       case SMDSEntity_Hexa:
1381       case SMDSEntity_Quad_Hexa:
1382         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1383           connVariants = theHexTo5, nbTet = 5;
1384         else
1385           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1386         break;
1387       case SMDSEntity_Pyramid:
1388       case SMDSEntity_Quad_Pyramid:
1389         connVariants = thePyraTo2;  nbTet = 2;
1390         break;
1391       case SMDSEntity_Penta:
1392       case SMDSEntity_Quad_Penta:
1393         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1394         break;
1395       default:
1396         nbVariants = 0;
1397       }
1398       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1399       {
1400         // check method compliancy with adjacent tetras,
1401         // all found splits must be among facets of tetras described by this method
1402         method = TSplitMethod( nbTet, connVariants[variant] );
1403         if ( hasAdjacentSplits && method._nbTetra > 0 )
1404         {
1405           bool facetCreated = true;
1406           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1407           {
1408             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1409             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1410               facetCreated = method.hasFacet( *facet );
1411           }
1412           if ( !facetCreated )
1413             method = TSplitMethod(0); // incompatible method
1414         }
1415       }
1416     }
1417     if ( method._nbTetra < 1 )
1418     {
1419       // No standard method is applicable, use a generic solution:
1420       // each facet of a volume is split into triangles and
1421       // each of triangles and a volume barycenter form a tetrahedron.
1422
1423       int* connectivity = new int[ maxTetConnSize + 1 ];
1424       method._connectivity = connectivity;
1425       method._ownConn = true;
1426       method._baryNode = true;
1427
1428       int connSize = 0;
1429       int baryCenInd = vol.NbNodes();
1430       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1431       {
1432         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1433         const int*   nInd = vol.GetFaceNodesIndices( iF );
1434         // find common node of triangle facets of tetra to create
1435         int iCommon = 0; // index in linear numeration
1436         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1437         if ( !triaSplits.empty() )
1438         {
1439           // by found facets
1440           const TTriangleFacet* facet = &triaSplits.front();
1441           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1442             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1443                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1444               break;
1445         }
1446         else if ( nbNodes > 3 && !is24TetMode )
1447         {
1448           // find the best method of splitting into triangles by aspect ratio
1449           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1450           map< double, int > badness2iCommon;
1451           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1452           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1453           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1454             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1455             {
1456               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1457                                       nodes[ iQ*((iLast-1)%nbNodes)],
1458                                       nodes[ iQ*((iLast  )%nbNodes)]);
1459               double badness = getBadRate( &tria, aspectRatio );
1460               badness2iCommon.insert( make_pair( badness, iCommon ));
1461             }
1462           // use iCommon with lowest badness
1463           iCommon = badness2iCommon.begin()->second;
1464         }
1465         if ( iCommon >= nbNodes )
1466           iCommon = 0; // something wrong
1467
1468         // fill connectivity of tetrahedra based on a current face
1469         int nbTet = nbNodes - 2;
1470         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1471         {
1472           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1473           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1474           nbTet = nbNodes;
1475           for ( int i = 0; i < nbTet; ++i )
1476           {
1477             int i1 = i, i2 = (i+1) % nbNodes;
1478             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1479             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1480             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1481             connectivity[ connSize++ ] = faceBaryCenInd;
1482             connectivity[ connSize++ ] = baryCenInd;
1483           }
1484         }
1485         else
1486         {
1487           for ( int i = 0; i < nbTet; ++i )
1488           {
1489             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1490             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1491             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1492             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1493             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1494             connectivity[ connSize++ ] = baryCenInd;
1495           }
1496         }
1497         method._nbTetra += nbTet;
1498       }
1499       connectivity[ connSize++ ] = -1;
1500     }
1501     return method;
1502   }
1503   //================================================================================
1504   /*!
1505    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1506    */
1507   //================================================================================
1508
1509   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1510   {
1511     // find the tetrahedron including the three nodes of facet
1512     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1513     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1514     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1515     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1516     while ( volIt1->more() )
1517     {
1518       const SMDS_MeshElement* v = volIt1->next();
1519       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1520         continue;
1521       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1522       while ( volIt2->more() )
1523         if ( v != volIt2->next() )
1524           continue;
1525       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1526       while ( volIt3->more() )
1527         if ( v == volIt3->next() )
1528           return true;
1529     }
1530     return false;
1531   }
1532
1533   //=======================================================================
1534   /*!
1535    * \brief A key of a face of volume
1536    */
1537   //=======================================================================
1538
1539   struct TVolumeFaceKey: pair< int, pair< int, int> >
1540   {
1541     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1542     {
1543       TIDSortedNodeSet sortedNodes;
1544       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1545       int nbNodes = vol.NbFaceNodes( iF );
1546       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1547       for ( int i = 0; i < nbNodes; i += iQ )
1548         sortedNodes.insert( fNodes[i] );
1549       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1550       first = (*(n++))->GetID();
1551       second.first = (*(n++))->GetID();
1552       second.second = (*(n++))->GetID();
1553     }
1554   };
1555 } // namespace
1556
1557 //=======================================================================
1558 //function : SplitVolumesIntoTetra
1559 //purpose  : Split volumic elements into tetrahedra.
1560 //=======================================================================
1561
1562 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1563                                               const int                theMethodFlags)
1564 {
1565   // std-like iterator on coordinates of nodes of mesh element
1566   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1567   NXyzIterator xyzEnd;
1568
1569   SMDS_VolumeTool    volTool;
1570   SMESH_MesherHelper helper( *GetMesh());
1571
1572   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1573   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1574   
1575   SMESH_SequenceOfElemPtr newNodes, newElems;
1576
1577   // map face of volume to it's baricenrtic node
1578   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1579   double bc[3];
1580
1581   TIDSortedElemSet::const_iterator elem = theElems.begin();
1582   for ( ; elem != theElems.end(); ++elem )
1583   {
1584     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1585     if ( geomType <= SMDSEntity_Quad_Tetra )
1586       continue; // tetra or face or ...
1587
1588     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1589
1590     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1591     if ( splitMethod._nbTetra < 1 ) continue;
1592
1593     // find submesh to add new tetras to
1594     if ( !subMesh || !subMesh->Contains( *elem ))
1595     {
1596       int shapeID = FindShape( *elem );
1597       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1598       subMesh = GetMeshDS()->MeshElements( shapeID );
1599     }
1600     int iQ;
1601     if ( (*elem)->IsQuadratic() )
1602     {
1603       iQ = 2;
1604       // add quadratic links to the helper
1605       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1606       {
1607         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1608         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1609           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1610       }
1611       helper.SetIsQuadratic( true );
1612     }
1613     else
1614     {
1615       iQ = 1;
1616       helper.SetIsQuadratic( false );
1617     }
1618     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1619     helper.SetElementsOnShape( true );
1620     if ( splitMethod._baryNode )
1621     {
1622       // make a node at barycenter
1623       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1624       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1625       nodes.push_back( gcNode );
1626       newNodes.Append( gcNode );
1627     }
1628     if ( !splitMethod._faceBaryNode.empty() )
1629     {
1630       // make or find baricentric nodes of faces
1631       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1632       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1633       {
1634         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1635           volFace2BaryNode.insert
1636           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1637         if ( !f_n->second )
1638         {
1639           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1640           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1641         }
1642         nodes.push_back( iF_n->second = f_n->second );
1643       }
1644     }
1645
1646     // make tetras
1647     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1648     const int* tetConn = splitMethod._connectivity;
1649     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1650       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1651                                                        nodes[ tetConn[1] ],
1652                                                        nodes[ tetConn[2] ],
1653                                                        nodes[ tetConn[3] ]));
1654
1655     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1656
1657     // Split faces on sides of the split volume
1658
1659     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1660     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1661     {
1662       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1663       if ( nbNodes < 4 ) continue;
1664
1665       // find an existing face
1666       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1667                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1668       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1669       {
1670         // make triangles
1671         helper.SetElementsOnShape( false );
1672         vector< const SMDS_MeshElement* > triangles;
1673
1674         // find submesh to add new triangles in
1675         if ( !fSubMesh || !fSubMesh->Contains( face ))
1676         {
1677           int shapeID = FindShape( face );
1678           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1679         }
1680         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1681         if ( iF_n != splitMethod._faceBaryNode.end() )
1682         {
1683           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1684           {
1685             const SMDS_MeshNode* n1 = fNodes[iN];
1686             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1687             const SMDS_MeshNode *n3 = iF_n->second;
1688             if ( !volTool.IsFaceExternal( iF ))
1689               swap( n2, n3 );
1690             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1691
1692             if ( fSubMesh && n3->getshapeId() < 1 )
1693               fSubMesh->AddNode( n3 );
1694           }
1695         }
1696         else
1697         {
1698           // among possible triangles create ones discribed by split method
1699           const int* nInd = volTool.GetFaceNodesIndices( iF );
1700           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1701           int iCom = 0; // common node of triangle faces to split into
1702           list< TTriangleFacet > facets;
1703           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1704           {
1705             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1706                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1707                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1708             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1709                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1710                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1711             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1712             {
1713               facets.push_back( t012 );
1714               facets.push_back( t023 );
1715               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1716                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1717                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1718                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1719               break;
1720             }
1721           }
1722           list< TTriangleFacet >::iterator facet = facets.begin();
1723           for ( ; facet != facets.end(); ++facet )
1724           {
1725             if ( !volTool.IsFaceExternal( iF ))
1726               swap( facet->_n2, facet->_n3 );
1727             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1728                                                  volNodes[ facet->_n2 ],
1729                                                  volNodes[ facet->_n3 ]));
1730           }
1731         }
1732         for ( int i = 0; i < triangles.size(); ++i )
1733         {
1734           if ( !triangles[i] ) continue;
1735           if ( fSubMesh )
1736             fSubMesh->AddElement( triangles[i]);
1737           newElems.Append( triangles[i] );
1738         }
1739         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1740         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1741       }
1742
1743     } // loop on volume faces to split them into triangles
1744
1745     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1746
1747   } // loop on volumes to split
1748
1749   myLastCreatedNodes = newNodes;
1750   myLastCreatedElems = newElems;
1751 }
1752
1753 //=======================================================================
1754 //function : AddToSameGroups
1755 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1756 //=======================================================================
1757
1758 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1759                                         const SMDS_MeshElement* elemInGroups,
1760                                         SMESHDS_Mesh *          aMesh)
1761 {
1762   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1763   if (!groups.empty()) {
1764     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1765     for ( ; grIt != groups.end(); grIt++ ) {
1766       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1767       if ( group && group->Contains( elemInGroups ))
1768         group->SMDSGroup().Add( elemToAdd );
1769     }
1770   }
1771 }
1772
1773
1774 //=======================================================================
1775 //function : RemoveElemFromGroups
1776 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1777 //=======================================================================
1778 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1779                                              SMESHDS_Mesh *          aMesh)
1780 {
1781   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1782   if (!groups.empty())
1783   {
1784     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1785     for (; GrIt != groups.end(); GrIt++)
1786     {
1787       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1788       if (!grp || grp->IsEmpty()) continue;
1789       grp->SMDSGroup().Remove(removeelem);
1790     }
1791   }
1792 }
1793
1794 //================================================================================
1795 /*!
1796  * \brief Replace elemToRm by elemToAdd in the all groups
1797  */
1798 //================================================================================
1799
1800 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1801                                             const SMDS_MeshElement* elemToAdd,
1802                                             SMESHDS_Mesh *          aMesh)
1803 {
1804   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1805   if (!groups.empty()) {
1806     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1807     for ( ; grIt != groups.end(); grIt++ ) {
1808       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1809       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1810         group->SMDSGroup().Add( elemToAdd );
1811     }
1812   }
1813 }
1814
1815 //================================================================================
1816 /*!
1817  * \brief Replace elemToRm by elemToAdd in the all groups
1818  */
1819 //================================================================================
1820
1821 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1822                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1823                                             SMESHDS_Mesh *                         aMesh)
1824 {
1825   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1826   if (!groups.empty())
1827   {
1828     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1829     for ( ; grIt != groups.end(); grIt++ ) {
1830       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1831       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1832         for ( int i = 0; i < elemToAdd.size(); ++i )
1833           group->SMDSGroup().Add( elemToAdd[ i ] );
1834     }
1835   }
1836 }
1837
1838 //=======================================================================
1839 //function : QuadToTri
1840 //purpose  : Cut quadrangles into triangles.
1841 //           theCrit is used to select a diagonal to cut
1842 //=======================================================================
1843
1844 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1845                                   const bool         the13Diag)
1846 {
1847   myLastCreatedElems.Clear();
1848   myLastCreatedNodes.Clear();
1849
1850   MESSAGE( "::QuadToTri()" );
1851
1852   SMESHDS_Mesh * aMesh = GetMeshDS();
1853
1854   Handle(Geom_Surface) surface;
1855   SMESH_MesherHelper   helper( *GetMesh() );
1856
1857   TIDSortedElemSet::iterator itElem;
1858   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1859     const SMDS_MeshElement* elem = *itElem;
1860     if ( !elem || elem->GetType() != SMDSAbs_Face )
1861       continue;
1862     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1863     if(!isquad) continue;
1864
1865     if(elem->NbNodes()==4) {
1866       // retrieve element nodes
1867       const SMDS_MeshNode* aNodes [4];
1868       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1869       int i = 0;
1870       while ( itN->more() )
1871         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1872
1873       int aShapeId = FindShape( elem );
1874       const SMDS_MeshElement* newElem1 = 0;
1875       const SMDS_MeshElement* newElem2 = 0;
1876       if ( the13Diag ) {
1877         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1878         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1879       }
1880       else {
1881         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1882         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1883       }
1884       myLastCreatedElems.Append(newElem1);
1885       myLastCreatedElems.Append(newElem2);
1886       // put a new triangle on the same shape and add to the same groups
1887       if ( aShapeId )
1888         {
1889           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1890           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1891         }
1892       AddToSameGroups( newElem1, elem, aMesh );
1893       AddToSameGroups( newElem2, elem, aMesh );
1894       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1895       aMesh->RemoveElement( elem );
1896     }
1897
1898     // Quadratic quadrangle
1899
1900     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1901
1902       // get surface elem is on
1903       int aShapeId = FindShape( elem );
1904       if ( aShapeId != helper.GetSubShapeID() ) {
1905         surface.Nullify();
1906         TopoDS_Shape shape;
1907         if ( aShapeId > 0 )
1908           shape = aMesh->IndexToShape( aShapeId );
1909         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1910           TopoDS_Face face = TopoDS::Face( shape );
1911           surface = BRep_Tool::Surface( face );
1912           if ( !surface.IsNull() )
1913             helper.SetSubShape( shape );
1914         }
1915       }
1916
1917       const SMDS_MeshNode* aNodes [8];
1918       const SMDS_MeshNode* inFaceNode = 0;
1919       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1920       int i = 0;
1921       while ( itN->more() ) {
1922         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1923         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1924              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1925         {
1926           inFaceNode = aNodes[ i-1 ];
1927         }
1928       }
1929
1930       // find middle point for (0,1,2,3)
1931       // and create a node in this point;
1932       gp_XYZ p( 0,0,0 );
1933       if ( surface.IsNull() ) {
1934         for(i=0; i<4; i++)
1935           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1936         p /= 4;
1937       }
1938       else {
1939         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1940         gp_XY uv( 0,0 );
1941         for(i=0; i<4; i++)
1942           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1943         uv /= 4.;
1944         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1945       }
1946       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1947       myLastCreatedNodes.Append(newN);
1948
1949       // create a new element
1950       const SMDS_MeshElement* newElem1 = 0;
1951       const SMDS_MeshElement* newElem2 = 0;
1952       if ( the13Diag ) {
1953         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1954                                   aNodes[6], aNodes[7], newN );
1955         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1956                                   newN,      aNodes[4], aNodes[5] );
1957       }
1958       else {
1959         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1960                                   aNodes[7], aNodes[4], newN );
1961         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1962                                   newN,      aNodes[5], aNodes[6] );
1963       }
1964       myLastCreatedElems.Append(newElem1);
1965       myLastCreatedElems.Append(newElem2);
1966       // put a new triangle on the same shape and add to the same groups
1967       if ( aShapeId )
1968         {
1969           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1970           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1971         }
1972       AddToSameGroups( newElem1, elem, aMesh );
1973       AddToSameGroups( newElem2, elem, aMesh );
1974       aMesh->RemoveElement( elem );
1975     }
1976   }
1977
1978   return true;
1979 }
1980
1981 //=======================================================================
1982 //function : getAngle
1983 //purpose  :
1984 //=======================================================================
1985
1986 double getAngle(const SMDS_MeshElement * tr1,
1987                 const SMDS_MeshElement * tr2,
1988                 const SMDS_MeshNode *    n1,
1989                 const SMDS_MeshNode *    n2)
1990 {
1991   double angle = 2*PI; // bad angle
1992
1993   // get normals
1994   SMESH::Controls::TSequenceOfXYZ P1, P2;
1995   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1996        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1997     return angle;
1998   gp_Vec N1,N2;
1999   if(!tr1->IsQuadratic())
2000     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2001   else
2002     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2003   if ( N1.SquareMagnitude() <= gp::Resolution() )
2004     return angle;
2005   if(!tr2->IsQuadratic())
2006     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2007   else
2008     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2009   if ( N2.SquareMagnitude() <= gp::Resolution() )
2010     return angle;
2011
2012   // find the first diagonal node n1 in the triangles:
2013   // take in account a diagonal link orientation
2014   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2015   for ( int t = 0; t < 2; t++ ) {
2016     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2017     int i = 0, iDiag = -1;
2018     while ( it->more()) {
2019       const SMDS_MeshElement *n = it->next();
2020       if ( n == n1 || n == n2 ) {
2021         if ( iDiag < 0)
2022           iDiag = i;
2023         else {
2024           if ( i - iDiag == 1 )
2025             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2026           else
2027             nFirst[ t ] = n;
2028           break;
2029         }
2030       }
2031       i++;
2032     }
2033   }
2034   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2035     N2.Reverse();
2036
2037   angle = N1.Angle( N2 );
2038   //SCRUTE( angle );
2039   return angle;
2040 }
2041
2042 // =================================================
2043 // class generating a unique ID for a pair of nodes
2044 // and able to return nodes by that ID
2045 // =================================================
2046 class LinkID_Gen {
2047 public:
2048
2049   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2050     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2051   {}
2052
2053   long GetLinkID (const SMDS_MeshNode * n1,
2054                   const SMDS_MeshNode * n2) const
2055   {
2056     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2057   }
2058
2059   bool GetNodes (const long             theLinkID,
2060                  const SMDS_MeshNode* & theNode1,
2061                  const SMDS_MeshNode* & theNode2) const
2062   {
2063     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2064     if ( !theNode1 ) return false;
2065     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2066     if ( !theNode2 ) return false;
2067     return true;
2068   }
2069
2070 private:
2071   LinkID_Gen();
2072   const SMESHDS_Mesh* myMesh;
2073   long                myMaxID;
2074 };
2075
2076
2077 //=======================================================================
2078 //function : TriToQuad
2079 //purpose  : Fuse neighbour triangles into quadrangles.
2080 //           theCrit is used to select a neighbour to fuse with.
2081 //           theMaxAngle is a max angle between element normals at which
2082 //           fusion is still performed.
2083 //=======================================================================
2084
2085 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2086                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2087                                   const double                         theMaxAngle)
2088 {
2089   myLastCreatedElems.Clear();
2090   myLastCreatedNodes.Clear();
2091
2092   MESSAGE( "::TriToQuad()" );
2093
2094   if ( !theCrit.get() )
2095     return false;
2096
2097   SMESHDS_Mesh * aMesh = GetMeshDS();
2098
2099   // Prepare data for algo: build
2100   // 1. map of elements with their linkIDs
2101   // 2. map of linkIDs with their elements
2102
2103   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2104   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2105   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2106   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2107
2108   TIDSortedElemSet::iterator itElem;
2109   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2110     const SMDS_MeshElement* elem = *itElem;
2111     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2112     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2113     if(!IsTria) continue;
2114
2115     // retrieve element nodes
2116     const SMDS_MeshNode* aNodes [4];
2117     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2118     int i = 0;
2119     while ( i<3 )
2120       aNodes[ i++ ] = cast2Node( itN->next() );
2121     aNodes[ 3 ] = aNodes[ 0 ];
2122
2123     // fill maps
2124     for ( i = 0; i < 3; i++ ) {
2125       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2126       // check if elements sharing a link can be fused
2127       itLE = mapLi_listEl.find( link );
2128       if ( itLE != mapLi_listEl.end() ) {
2129         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2130           continue;
2131         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2132         //if ( FindShape( elem ) != FindShape( elem2 ))
2133         //  continue; // do not fuse triangles laying on different shapes
2134         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2135           continue; // avoid making badly shaped quads
2136         (*itLE).second.push_back( elem );
2137       }
2138       else {
2139         mapLi_listEl[ link ].push_back( elem );
2140       }
2141       mapEl_setLi [ elem ].insert( link );
2142     }
2143   }
2144   // Clean the maps from the links shared by a sole element, ie
2145   // links to which only one element is bound in mapLi_listEl
2146
2147   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2148     int nbElems = (*itLE).second.size();
2149     if ( nbElems < 2  ) {
2150       const SMDS_MeshElement* elem = (*itLE).second.front();
2151       SMESH_TLink link = (*itLE).first;
2152       mapEl_setLi[ elem ].erase( link );
2153       if ( mapEl_setLi[ elem ].empty() )
2154         mapEl_setLi.erase( elem );
2155     }
2156   }
2157
2158   // Algo: fuse triangles into quadrangles
2159
2160   while ( ! mapEl_setLi.empty() ) {
2161     // Look for the start element:
2162     // the element having the least nb of shared links
2163     const SMDS_MeshElement* startElem = 0;
2164     int minNbLinks = 4;
2165     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2166       int nbLinks = (*itEL).second.size();
2167       if ( nbLinks < minNbLinks ) {
2168         startElem = (*itEL).first;
2169         minNbLinks = nbLinks;
2170         if ( minNbLinks == 1 )
2171           break;
2172       }
2173     }
2174
2175     // search elements to fuse starting from startElem or links of elements
2176     // fused earlyer - startLinks
2177     list< SMESH_TLink > startLinks;
2178     while ( startElem || !startLinks.empty() ) {
2179       while ( !startElem && !startLinks.empty() ) {
2180         // Get an element to start, by a link
2181         SMESH_TLink linkId = startLinks.front();
2182         startLinks.pop_front();
2183         itLE = mapLi_listEl.find( linkId );
2184         if ( itLE != mapLi_listEl.end() ) {
2185           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2186           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2187           for ( ; itE != listElem.end() ; itE++ )
2188             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2189               startElem = (*itE);
2190           mapLi_listEl.erase( itLE );
2191         }
2192       }
2193
2194       if ( startElem ) {
2195         // Get candidates to be fused
2196         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2197         const SMESH_TLink *link12, *link13;
2198         startElem = 0;
2199         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2200         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2201         ASSERT( !setLi.empty() );
2202         set< SMESH_TLink >::iterator itLi;
2203         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2204         {
2205           const SMESH_TLink & link = (*itLi);
2206           itLE = mapLi_listEl.find( link );
2207           if ( itLE == mapLi_listEl.end() )
2208             continue;
2209
2210           const SMDS_MeshElement* elem = (*itLE).second.front();
2211           if ( elem == tr1 )
2212             elem = (*itLE).second.back();
2213           mapLi_listEl.erase( itLE );
2214           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2215             continue;
2216           if ( tr2 ) {
2217             tr3 = elem;
2218             link13 = &link;
2219           }
2220           else {
2221             tr2 = elem;
2222             link12 = &link;
2223           }
2224
2225           // add other links of elem to list of links to re-start from
2226           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2227           set< SMESH_TLink >::iterator it;
2228           for ( it = links.begin(); it != links.end(); it++ ) {
2229             const SMESH_TLink& link2 = (*it);
2230             if ( link2 != link )
2231               startLinks.push_back( link2 );
2232           }
2233         }
2234
2235         // Get nodes of possible quadrangles
2236         const SMDS_MeshNode *n12 [4], *n13 [4];
2237         bool Ok12 = false, Ok13 = false;
2238         const SMDS_MeshNode *linkNode1, *linkNode2;
2239         if(tr2) {
2240           linkNode1 = link12->first;
2241           linkNode2 = link12->second;
2242           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2243             Ok12 = true;
2244         }
2245         if(tr3) {
2246           linkNode1 = link13->first;
2247           linkNode2 = link13->second;
2248           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2249             Ok13 = true;
2250         }
2251
2252         // Choose a pair to fuse
2253         if ( Ok12 && Ok13 ) {
2254           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2255           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2256           double aBadRate12 = getBadRate( &quad12, theCrit );
2257           double aBadRate13 = getBadRate( &quad13, theCrit );
2258           if (  aBadRate13 < aBadRate12 )
2259             Ok12 = false;
2260           else
2261             Ok13 = false;
2262         }
2263
2264         // Make quadrangles
2265         // and remove fused elems and removed links from the maps
2266         mapEl_setLi.erase( tr1 );
2267         if ( Ok12 ) {
2268           mapEl_setLi.erase( tr2 );
2269           mapLi_listEl.erase( *link12 );
2270           if(tr1->NbNodes()==3) {
2271             const SMDS_MeshElement* newElem = 0;
2272             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2273             myLastCreatedElems.Append(newElem);
2274             AddToSameGroups( newElem, tr1, aMesh );
2275             int aShapeId = tr1->getshapeId();
2276             if ( aShapeId )
2277               {
2278                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2279               }
2280             aMesh->RemoveElement( tr1 );
2281             aMesh->RemoveElement( tr2 );
2282           }
2283           else {
2284             const SMDS_MeshNode* N1 [6];
2285             const SMDS_MeshNode* N2 [6];
2286             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2287             // now we receive following N1 and N2 (using numeration as above image)
2288             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2289             // i.e. first nodes from both arrays determ new diagonal
2290             const SMDS_MeshNode* aNodes[8];
2291             aNodes[0] = N1[0];
2292             aNodes[1] = N1[1];
2293             aNodes[2] = N2[0];
2294             aNodes[3] = N2[1];
2295             aNodes[4] = N1[3];
2296             aNodes[5] = N2[5];
2297             aNodes[6] = N2[3];
2298             aNodes[7] = N1[5];
2299             const SMDS_MeshElement* newElem = 0;
2300             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2301                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2302             myLastCreatedElems.Append(newElem);
2303             AddToSameGroups( newElem, tr1, aMesh );
2304             int aShapeId = tr1->getshapeId();
2305             if ( aShapeId )
2306               {
2307                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2308               }
2309             aMesh->RemoveElement( tr1 );
2310             aMesh->RemoveElement( tr2 );
2311             // remove middle node (9)
2312             GetMeshDS()->RemoveNode( N1[4] );
2313           }
2314         }
2315         else if ( Ok13 ) {
2316           mapEl_setLi.erase( tr3 );
2317           mapLi_listEl.erase( *link13 );
2318           if(tr1->NbNodes()==3) {
2319             const SMDS_MeshElement* newElem = 0;
2320             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2321             myLastCreatedElems.Append(newElem);
2322             AddToSameGroups( newElem, tr1, aMesh );
2323             int aShapeId = tr1->getshapeId();
2324             if ( aShapeId )
2325               {
2326                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2327               }
2328             aMesh->RemoveElement( tr1 );
2329             aMesh->RemoveElement( tr3 );
2330           }
2331           else {
2332             const SMDS_MeshNode* N1 [6];
2333             const SMDS_MeshNode* N2 [6];
2334             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2335             // now we receive following N1 and N2 (using numeration as above image)
2336             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2337             // i.e. first nodes from both arrays determ new diagonal
2338             const SMDS_MeshNode* aNodes[8];
2339             aNodes[0] = N1[0];
2340             aNodes[1] = N1[1];
2341             aNodes[2] = N2[0];
2342             aNodes[3] = N2[1];
2343             aNodes[4] = N1[3];
2344             aNodes[5] = N2[5];
2345             aNodes[6] = N2[3];
2346             aNodes[7] = N1[5];
2347             const SMDS_MeshElement* newElem = 0;
2348             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2349                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2350             myLastCreatedElems.Append(newElem);
2351             AddToSameGroups( newElem, tr1, aMesh );
2352             int aShapeId = tr1->getshapeId();
2353             if ( aShapeId )
2354               {
2355                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2356               }
2357             aMesh->RemoveElement( tr1 );
2358             aMesh->RemoveElement( tr3 );
2359             // remove middle node (9)
2360             GetMeshDS()->RemoveNode( N1[4] );
2361           }
2362         }
2363
2364         // Next element to fuse: the rejected one
2365         if ( tr3 )
2366           startElem = Ok12 ? tr3 : tr2;
2367
2368       } // if ( startElem )
2369     } // while ( startElem || !startLinks.empty() )
2370   } // while ( ! mapEl_setLi.empty() )
2371
2372   return true;
2373 }
2374
2375
2376 /*#define DUMPSO(txt) \
2377 //  cout << txt << endl;
2378 //=============================================================================
2379 //
2380 //
2381 //
2382 //=============================================================================
2383 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2384 {
2385 if ( i1 == i2 )
2386 return;
2387 int tmp = idNodes[ i1 ];
2388 idNodes[ i1 ] = idNodes[ i2 ];
2389 idNodes[ i2 ] = tmp;
2390 gp_Pnt Ptmp = P[ i1 ];
2391 P[ i1 ] = P[ i2 ];
2392 P[ i2 ] = Ptmp;
2393 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2394 }
2395
2396 //=======================================================================
2397 //function : SortQuadNodes
2398 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2399 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2400 //           1 or 2 else 0.
2401 //=======================================================================
2402
2403 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2404 int               idNodes[] )
2405 {
2406   gp_Pnt P[4];
2407   int i;
2408   for ( i = 0; i < 4; i++ ) {
2409     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2410     if ( !n ) return 0;
2411     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2412   }
2413
2414   gp_Vec V1(P[0], P[1]);
2415   gp_Vec V2(P[0], P[2]);
2416   gp_Vec V3(P[0], P[3]);
2417
2418   gp_Vec Cross1 = V1 ^ V2;
2419   gp_Vec Cross2 = V2 ^ V3;
2420
2421   i = 0;
2422   if (Cross1.Dot(Cross2) < 0)
2423   {
2424     Cross1 = V2 ^ V1;
2425     Cross2 = V1 ^ V3;
2426
2427     if (Cross1.Dot(Cross2) < 0)
2428       i = 2;
2429     else
2430       i = 1;
2431     swap ( i, i + 1, idNodes, P );
2432
2433     //     for ( int ii = 0; ii < 4; ii++ ) {
2434     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2435     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2436     //     }
2437   }
2438   return i;
2439 }
2440
2441 //=======================================================================
2442 //function : SortHexaNodes
2443 //purpose  : Set 8 nodes of a hexahedron in a good order.
2444 //           Return success status
2445 //=======================================================================
2446
2447 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2448                                       int               idNodes[] )
2449 {
2450   gp_Pnt P[8];
2451   int i;
2452   DUMPSO( "INPUT: ========================================");
2453   for ( i = 0; i < 8; i++ ) {
2454     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2455     if ( !n ) return false;
2456     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2457     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2458   }
2459   DUMPSO( "========================================");
2460
2461
2462   set<int> faceNodes;  // ids of bottom face nodes, to be found
2463   set<int> checkedId1; // ids of tried 2-nd nodes
2464   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2465   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2466   int iMin, iLoop1 = 0;
2467
2468   // Loop to try the 2-nd nodes
2469
2470   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2471   {
2472     // Find not checked 2-nd node
2473     for ( i = 1; i < 8; i++ )
2474       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2475         int id1 = idNodes[i];
2476         swap ( 1, i, idNodes, P );
2477         checkedId1.insert ( id1 );
2478         break;
2479       }
2480
2481     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2482     // ie that all but meybe one (id3 which is on the same face) nodes
2483     // lay on the same side from the triangle plane.
2484
2485     bool manyInPlane = false; // more than 4 nodes lay in plane
2486     int iLoop2 = 0;
2487     while ( ++iLoop2 < 6 ) {
2488
2489       // get 1-2-3 plane coeffs
2490       Standard_Real A, B, C, D;
2491       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2492       if ( N.SquareMagnitude() > gp::Resolution() )
2493       {
2494         gp_Pln pln ( P[0], N );
2495         pln.Coefficients( A, B, C, D );
2496
2497         // find the node (iMin) closest to pln
2498         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2499         set<int> idInPln;
2500         for ( i = 3; i < 8; i++ ) {
2501           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2502           if ( fabs( dist[i] ) < minDist ) {
2503             minDist = fabs( dist[i] );
2504             iMin = i;
2505           }
2506           if ( fabs( dist[i] ) <= tol )
2507             idInPln.insert( idNodes[i] );
2508         }
2509
2510         // there should not be more than 4 nodes in bottom plane
2511         if ( idInPln.size() > 1 )
2512         {
2513           DUMPSO( "### idInPln.size() = " << idInPln.size());
2514           // idInPlane does not contain the first 3 nodes
2515           if ( manyInPlane || idInPln.size() == 5)
2516             return false; // all nodes in one plane
2517           manyInPlane = true;
2518
2519           // set the 1-st node to be not in plane
2520           for ( i = 3; i < 8; i++ ) {
2521             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2522               DUMPSO( "### Reset 0-th node");
2523               swap( 0, i, idNodes, P );
2524               break;
2525             }
2526           }
2527
2528           // reset to re-check second nodes
2529           leastDist = DBL_MAX;
2530           faceNodes.clear();
2531           checkedId1.clear();
2532           iLoop1 = 0;
2533           break; // from iLoop2;
2534         }
2535
2536         // check that the other 4 nodes are on the same side
2537         bool sameSide = true;
2538         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2539         for ( i = 3; sameSide && i < 8; i++ ) {
2540           if ( i != iMin )
2541             sameSide = ( isNeg == dist[i] <= 0.);
2542         }
2543
2544         // keep best solution
2545         if ( sameSide && minDist < leastDist ) {
2546           leastDist = minDist;
2547           faceNodes.clear();
2548           faceNodes.insert( idNodes[ 1 ] );
2549           faceNodes.insert( idNodes[ 2 ] );
2550           faceNodes.insert( idNodes[ iMin ] );
2551           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2552                   << " leastDist = " << leastDist);
2553           if ( leastDist <= DBL_MIN )
2554             break;
2555         }
2556       }
2557
2558       // set next 3-d node to check
2559       int iNext = 2 + iLoop2;
2560       if ( iNext < 8 ) {
2561         DUMPSO( "Try 2-nd");
2562         swap ( 2, iNext, idNodes, P );
2563       }
2564     } // while ( iLoop2 < 6 )
2565   } // iLoop1
2566
2567   if ( faceNodes.empty() ) return false;
2568
2569   // Put the faceNodes in proper places
2570   for ( i = 4; i < 8; i++ ) {
2571     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2572       // find a place to put
2573       int iTo = 1;
2574       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2575         iTo++;
2576       DUMPSO( "Set faceNodes");
2577       swap ( iTo, i, idNodes, P );
2578     }
2579   }
2580
2581
2582   // Set nodes of the found bottom face in good order
2583   DUMPSO( " Found bottom face: ");
2584   i = SortQuadNodes( theMesh, idNodes );
2585   if ( i ) {
2586     gp_Pnt Ptmp = P[ i ];
2587     P[ i ] = P[ i+1 ];
2588     P[ i+1 ] = Ptmp;
2589   }
2590   //   else
2591   //     for ( int ii = 0; ii < 4; ii++ ) {
2592   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2593   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2594   //    }
2595
2596   // Gravity center of the top and bottom faces
2597   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2598   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2599
2600   // Get direction from the bottom to the top face
2601   gp_Vec upDir ( aGCb, aGCt );
2602   Standard_Real upDirSize = upDir.Magnitude();
2603   if ( upDirSize <= gp::Resolution() ) return false;
2604   upDir / upDirSize;
2605
2606   // Assure that the bottom face normal points up
2607   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2608   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2609   if ( Nb.Dot( upDir ) < 0 ) {
2610     DUMPSO( "Reverse bottom face");
2611     swap( 1, 3, idNodes, P );
2612   }
2613
2614   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2615   Standard_Real minDist = DBL_MAX;
2616   for ( i = 4; i < 8; i++ ) {
2617     // projection of P[i] to the plane defined by P[0] and upDir
2618     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2619     Standard_Real sqDist = P[0].SquareDistance( Pp );
2620     if ( sqDist < minDist ) {
2621       minDist = sqDist;
2622       iMin = i;
2623     }
2624   }
2625   DUMPSO( "Set 4-th");
2626   swap ( 4, iMin, idNodes, P );
2627
2628   // Set nodes of the top face in good order
2629   DUMPSO( "Sort top face");
2630   i = SortQuadNodes( theMesh, &idNodes[4] );
2631   if ( i ) {
2632     i += 4;
2633     gp_Pnt Ptmp = P[ i ];
2634     P[ i ] = P[ i+1 ];
2635     P[ i+1 ] = Ptmp;
2636   }
2637
2638   // Assure that direction of the top face normal is from the bottom face
2639   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2640   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2641   if ( Nt.Dot( upDir ) < 0 ) {
2642     DUMPSO( "Reverse top face");
2643     swap( 5, 7, idNodes, P );
2644   }
2645
2646   //   DUMPSO( "OUTPUT: ========================================");
2647   //   for ( i = 0; i < 8; i++ ) {
2648   //     float *p = ugrid->GetPoint(idNodes[i]);
2649   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2650   //   }
2651
2652   return true;
2653 }*/
2654
2655 //================================================================================
2656 /*!
2657  * \brief Return nodes linked to the given one
2658  * \param theNode - the node
2659  * \param linkedNodes - the found nodes
2660  * \param type - the type of elements to check
2661  *
2662  * Medium nodes are ignored
2663  */
2664 //================================================================================
2665
2666 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2667                                        TIDSortedElemSet &   linkedNodes,
2668                                        SMDSAbs_ElementType  type )
2669 {
2670   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2671   while ( elemIt->more() )
2672   {
2673     const SMDS_MeshElement* elem = elemIt->next();
2674     if(elem->GetType() == SMDSAbs_0DElement)
2675       continue;
2676     
2677     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2678     if ( elem->GetType() == SMDSAbs_Volume )
2679     {
2680       SMDS_VolumeTool vol( elem );
2681       while ( nodeIt->more() ) {
2682         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2683         if ( theNode != n && vol.IsLinked( theNode, n ))
2684           linkedNodes.insert( n );
2685       }
2686     }
2687     else
2688     {
2689       for ( int i = 0; nodeIt->more(); ++i ) {
2690         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2691         if ( n == theNode ) {
2692           int iBefore = i - 1;
2693           int iAfter  = i + 1;
2694           if ( elem->IsQuadratic() ) {
2695             int nb = elem->NbNodes() / 2;
2696             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2697             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2698           }
2699           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2700           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2701         }
2702       }
2703     }
2704   }
2705 }
2706
2707 //=======================================================================
2708 //function : laplacianSmooth
2709 //purpose  : pulls theNode toward the center of surrounding nodes directly
2710 //           connected to that node along an element edge
2711 //=======================================================================
2712
2713 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2714                      const Handle(Geom_Surface)&          theSurface,
2715                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2716 {
2717   // find surrounding nodes
2718
2719   TIDSortedElemSet nodeSet;
2720   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2721
2722   // compute new coodrs
2723
2724   double coord[] = { 0., 0., 0. };
2725   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2726   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2727     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2728     if ( theSurface.IsNull() ) { // smooth in 3D
2729       coord[0] += node->X();
2730       coord[1] += node->Y();
2731       coord[2] += node->Z();
2732     }
2733     else { // smooth in 2D
2734       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2735       gp_XY* uv = theUVMap[ node ];
2736       coord[0] += uv->X();
2737       coord[1] += uv->Y();
2738     }
2739   }
2740   int nbNodes = nodeSet.size();
2741   if ( !nbNodes )
2742     return;
2743   coord[0] /= nbNodes;
2744   coord[1] /= nbNodes;
2745
2746   if ( !theSurface.IsNull() ) {
2747     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2748     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2749     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2750     coord[0] = p3d.X();
2751     coord[1] = p3d.Y();
2752     coord[2] = p3d.Z();
2753   }
2754   else
2755     coord[2] /= nbNodes;
2756
2757   // move node
2758
2759   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2760 }
2761
2762 //=======================================================================
2763 //function : centroidalSmooth
2764 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2765 //           surrounding elements
2766 //=======================================================================
2767
2768 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2769                       const Handle(Geom_Surface)&          theSurface,
2770                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2771 {
2772   gp_XYZ aNewXYZ(0.,0.,0.);
2773   SMESH::Controls::Area anAreaFunc;
2774   double totalArea = 0.;
2775   int nbElems = 0;
2776
2777   // compute new XYZ
2778
2779   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2780   while ( elemIt->more() )
2781   {
2782     const SMDS_MeshElement* elem = elemIt->next();
2783     nbElems++;
2784
2785     gp_XYZ elemCenter(0.,0.,0.);
2786     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2787     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2788     int nn = elem->NbNodes();
2789     if(elem->IsQuadratic()) nn = nn/2;
2790     int i=0;
2791     //while ( itN->more() ) {
2792     while ( i<nn ) {
2793       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2794       i++;
2795       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2796       aNodePoints.push_back( aP );
2797       if ( !theSurface.IsNull() ) { // smooth in 2D
2798         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2799         gp_XY* uv = theUVMap[ aNode ];
2800         aP.SetCoord( uv->X(), uv->Y(), 0. );
2801       }
2802       elemCenter += aP;
2803     }
2804     double elemArea = anAreaFunc.GetValue( aNodePoints );
2805     totalArea += elemArea;
2806     elemCenter /= nn;
2807     aNewXYZ += elemCenter * elemArea;
2808   }
2809   aNewXYZ /= totalArea;
2810   if ( !theSurface.IsNull() ) {
2811     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2812     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2813   }
2814
2815   // move node
2816
2817   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2818 }
2819
2820 //=======================================================================
2821 //function : getClosestUV
2822 //purpose  : return UV of closest projection
2823 //=======================================================================
2824
2825 static bool getClosestUV (Extrema_GenExtPS& projector,
2826                           const gp_Pnt&     point,
2827                           gp_XY &           result)
2828 {
2829   projector.Perform( point );
2830   if ( projector.IsDone() ) {
2831     double u, v, minVal = DBL_MAX;
2832     for ( int i = projector.NbExt(); i > 0; i-- )
2833 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
2834       if ( projector.SquareDistance( i ) < minVal ) {
2835         minVal = projector.SquareDistance( i );
2836 #else
2837       if ( projector.Value( i ) < minVal ) {
2838         minVal = projector.Value( i );
2839 #endif
2840         projector.Point( i ).Parameter( u, v );
2841       }
2842     result.SetCoord( u, v );
2843     return true;
2844   }
2845   return false;
2846 }
2847
2848 //=======================================================================
2849 //function : Smooth
2850 //purpose  : Smooth theElements during theNbIterations or until a worst
2851 //           element has aspect ratio <= theTgtAspectRatio.
2852 //           Aspect Ratio varies in range [1.0, inf].
2853 //           If theElements is empty, the whole mesh is smoothed.
2854 //           theFixedNodes contains additionally fixed nodes. Nodes built
2855 //           on edges and boundary nodes are always fixed.
2856 //=======================================================================
2857
2858 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2859                                set<const SMDS_MeshNode*> & theFixedNodes,
2860                                const SmoothMethod          theSmoothMethod,
2861                                const int                   theNbIterations,
2862                                double                      theTgtAspectRatio,
2863                                const bool                  the2D)
2864 {
2865   myLastCreatedElems.Clear();
2866   myLastCreatedNodes.Clear();
2867
2868   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2869
2870   if ( theTgtAspectRatio < 1.0 )
2871     theTgtAspectRatio = 1.0;
2872
2873   const double disttol = 1.e-16;
2874
2875   SMESH::Controls::AspectRatio aQualityFunc;
2876
2877   SMESHDS_Mesh* aMesh = GetMeshDS();
2878
2879   if ( theElems.empty() ) {
2880     // add all faces to theElems
2881     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2882     while ( fIt->more() ) {
2883       const SMDS_MeshElement* face = fIt->next();
2884       theElems.insert( face );
2885     }
2886   }
2887   // get all face ids theElems are on
2888   set< int > faceIdSet;
2889   TIDSortedElemSet::iterator itElem;
2890   if ( the2D )
2891     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2892       int fId = FindShape( *itElem );
2893       // check that corresponding submesh exists and a shape is face
2894       if (fId &&
2895           faceIdSet.find( fId ) == faceIdSet.end() &&
2896           aMesh->MeshElements( fId )) {
2897         TopoDS_Shape F = aMesh->IndexToShape( fId );
2898         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2899           faceIdSet.insert( fId );
2900       }
2901     }
2902   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2903
2904   // ===============================================
2905   // smooth elements on each TopoDS_Face separately
2906   // ===============================================
2907
2908   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2909   for ( ; fId != faceIdSet.rend(); ++fId ) {
2910     // get face surface and submesh
2911     Handle(Geom_Surface) surface;
2912     SMESHDS_SubMesh* faceSubMesh = 0;
2913     TopoDS_Face face;
2914     double fToler2 = 0, f,l;
2915     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2916     bool isUPeriodic = false, isVPeriodic = false;
2917     if ( *fId ) {
2918       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2919       surface = BRep_Tool::Surface( face );
2920       faceSubMesh = aMesh->MeshElements( *fId );
2921       fToler2 = BRep_Tool::Tolerance( face );
2922       fToler2 *= fToler2 * 10.;
2923       isUPeriodic = surface->IsUPeriodic();
2924       if ( isUPeriodic )
2925         surface->UPeriod();
2926       isVPeriodic = surface->IsVPeriodic();
2927       if ( isVPeriodic )
2928         surface->VPeriod();
2929       surface->Bounds( u1, u2, v1, v2 );
2930     }
2931     // ---------------------------------------------------------
2932     // for elements on a face, find movable and fixed nodes and
2933     // compute UV for them
2934     // ---------------------------------------------------------
2935     bool checkBoundaryNodes = false;
2936     bool isQuadratic = false;
2937     set<const SMDS_MeshNode*> setMovableNodes;
2938     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2939     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2940     list< const SMDS_MeshElement* > elemsOnFace;
2941
2942     Extrema_GenExtPS projector;
2943     GeomAdaptor_Surface surfAdaptor;
2944     if ( !surface.IsNull() ) {
2945       surfAdaptor.Load( surface );
2946       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2947     }
2948     int nbElemOnFace = 0;
2949     itElem = theElems.begin();
2950     // loop on not yet smoothed elements: look for elems on a face
2951     while ( itElem != theElems.end() ) {
2952       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2953         break; // all elements found
2954
2955       const SMDS_MeshElement* elem = *itElem;
2956       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2957            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2958         ++itElem;
2959         continue;
2960       }
2961       elemsOnFace.push_back( elem );
2962       theElems.erase( itElem++ );
2963       nbElemOnFace++;
2964
2965       if ( !isQuadratic )
2966         isQuadratic = elem->IsQuadratic();
2967
2968       // get movable nodes of elem
2969       const SMDS_MeshNode* node;
2970       SMDS_TypeOfPosition posType;
2971       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2972       int nn = 0, nbn =  elem->NbNodes();
2973       if(elem->IsQuadratic())
2974         nbn = nbn/2;
2975       while ( nn++ < nbn ) {
2976         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2977         const SMDS_PositionPtr& pos = node->GetPosition();
2978         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2979         if (posType != SMDS_TOP_EDGE &&
2980             posType != SMDS_TOP_VERTEX &&
2981             theFixedNodes.find( node ) == theFixedNodes.end())
2982         {
2983           // check if all faces around the node are on faceSubMesh
2984           // because a node on edge may be bound to face
2985           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2986           bool all = true;
2987           if ( faceSubMesh ) {
2988             while ( eIt->more() && all ) {
2989               const SMDS_MeshElement* e = eIt->next();
2990               all = faceSubMesh->Contains( e );
2991             }
2992           }
2993           if ( all )
2994             setMovableNodes.insert( node );
2995           else
2996             checkBoundaryNodes = true;
2997         }
2998         if ( posType == SMDS_TOP_3DSPACE )
2999           checkBoundaryNodes = true;
3000       }
3001
3002       if ( surface.IsNull() )
3003         continue;
3004
3005       // get nodes to check UV
3006       list< const SMDS_MeshNode* > uvCheckNodes;
3007       itN = elem->nodesIterator();
3008       nn = 0; nbn =  elem->NbNodes();
3009       if(elem->IsQuadratic())
3010         nbn = nbn/2;
3011       while ( nn++ < nbn ) {
3012         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3013         if ( uvMap.find( node ) == uvMap.end() )
3014           uvCheckNodes.push_back( node );
3015         // add nodes of elems sharing node
3016         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3017         //         while ( eIt->more() ) {
3018         //           const SMDS_MeshElement* e = eIt->next();
3019         //           if ( e != elem ) {
3020         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3021         //             while ( nIt->more() ) {
3022         //               const SMDS_MeshNode* n =
3023         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3024         //               if ( uvMap.find( n ) == uvMap.end() )
3025         //                 uvCheckNodes.push_back( n );
3026         //             }
3027         //           }
3028         //         }
3029       }
3030       // check UV on face
3031       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3032       for ( ; n != uvCheckNodes.end(); ++n ) {
3033         node = *n;
3034         gp_XY uv( 0, 0 );
3035         const SMDS_PositionPtr& pos = node->GetPosition();
3036         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3037         // get existing UV
3038         switch ( posType ) {
3039         case SMDS_TOP_FACE: {
3040           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3041           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3042           break;
3043         }
3044         case SMDS_TOP_EDGE: {
3045           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3046           Handle(Geom2d_Curve) pcurve;
3047           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3048             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3049           if ( !pcurve.IsNull() ) {
3050             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3051             uv = pcurve->Value( u ).XY();
3052           }
3053           break;
3054         }
3055         case SMDS_TOP_VERTEX: {
3056           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3057           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3058             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3059           break;
3060         }
3061         default:;
3062         }
3063         // check existing UV
3064         bool project = true;
3065         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3066         double dist1 = DBL_MAX, dist2 = 0;
3067         if ( posType != SMDS_TOP_3DSPACE ) {
3068           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3069           project = dist1 > fToler2;
3070         }
3071         if ( project ) { // compute new UV
3072           gp_XY newUV;
3073           if ( !getClosestUV( projector, pNode, newUV )) {
3074             MESSAGE("Node Projection Failed " << node);
3075           }
3076           else {
3077             if ( isUPeriodic )
3078               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3079             if ( isVPeriodic )
3080               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3081             // check new UV
3082             if ( posType != SMDS_TOP_3DSPACE )
3083               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3084             if ( dist2 < dist1 )
3085               uv = newUV;
3086           }
3087         }
3088         // store UV in the map
3089         listUV.push_back( uv );
3090         uvMap.insert( make_pair( node, &listUV.back() ));
3091       }
3092     } // loop on not yet smoothed elements
3093
3094     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3095       checkBoundaryNodes = true;
3096
3097     // fix nodes on mesh boundary
3098
3099     if ( checkBoundaryNodes ) {
3100       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3101       map< SMESH_TLink, int >::iterator link_nb;
3102       // put all elements links to linkNbMap
3103       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3104       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3105         const SMDS_MeshElement* elem = (*elemIt);
3106         int nbn =  elem->NbCornerNodes();
3107         // loop on elem links: insert them in linkNbMap
3108         for ( int iN = 0; iN < nbn; ++iN ) {
3109           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3110           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3111           SMESH_TLink link( n1, n2 );
3112           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3113           link_nb->second++;
3114         }
3115       }
3116       // remove nodes that are in links encountered only once from setMovableNodes
3117       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3118         if ( link_nb->second == 1 ) {
3119           setMovableNodes.erase( link_nb->first.node1() );
3120           setMovableNodes.erase( link_nb->first.node2() );
3121         }
3122       }
3123     }
3124
3125     // -----------------------------------------------------
3126     // for nodes on seam edge, compute one more UV ( uvMap2 );
3127     // find movable nodes linked to nodes on seam and which
3128     // are to be smoothed using the second UV ( uvMap2 )
3129     // -----------------------------------------------------
3130
3131     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3132     if ( !surface.IsNull() ) {
3133       TopExp_Explorer eExp( face, TopAbs_EDGE );
3134       for ( ; eExp.More(); eExp.Next() ) {
3135         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3136         if ( !BRep_Tool::IsClosed( edge, face ))
3137           continue;
3138         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3139         if ( !sm ) continue;
3140         // find out which parameter varies for a node on seam
3141         double f,l;
3142         gp_Pnt2d uv1, uv2;
3143         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3144         if ( pcurve.IsNull() ) continue;
3145         uv1 = pcurve->Value( f );
3146         edge.Reverse();
3147         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3148         if ( pcurve.IsNull() ) continue;
3149         uv2 = pcurve->Value( f );
3150         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3151         // assure uv1 < uv2
3152         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3153           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3154         }
3155         // get nodes on seam and its vertices
3156         list< const SMDS_MeshNode* > seamNodes;
3157         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3158         while ( nSeamIt->more() ) {
3159           const SMDS_MeshNode* node = nSeamIt->next();
3160           if ( !isQuadratic || !IsMedium( node ))
3161             seamNodes.push_back( node );
3162         }
3163         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3164         for ( ; vExp.More(); vExp.Next() ) {
3165           sm = aMesh->MeshElements( vExp.Current() );
3166           if ( sm ) {
3167             nSeamIt = sm->GetNodes();
3168             while ( nSeamIt->more() )
3169               seamNodes.push_back( nSeamIt->next() );
3170           }
3171         }
3172         // loop on nodes on seam
3173         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3174         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3175           const SMDS_MeshNode* nSeam = *noSeIt;
3176           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3177           if ( n_uv == uvMap.end() )
3178             continue;
3179           // set the first UV
3180           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3181           // set the second UV
3182           listUV.push_back( *n_uv->second );
3183           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3184           if ( uvMap2.empty() )
3185             uvMap2 = uvMap; // copy the uvMap contents
3186           uvMap2[ nSeam ] = &listUV.back();
3187
3188           // collect movable nodes linked to ones on seam in nodesNearSeam
3189           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3190           while ( eIt->more() ) {
3191             const SMDS_MeshElement* e = eIt->next();
3192             int nbUseMap1 = 0, nbUseMap2 = 0;
3193             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3194             int nn = 0, nbn =  e->NbNodes();
3195             if(e->IsQuadratic()) nbn = nbn/2;
3196             while ( nn++ < nbn )
3197             {
3198               const SMDS_MeshNode* n =
3199                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3200               if (n == nSeam ||
3201                   setMovableNodes.find( n ) == setMovableNodes.end() )
3202                 continue;
3203               // add only nodes being closer to uv2 than to uv1
3204               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3205                            0.5 * ( n->Y() + nSeam->Y() ),
3206                            0.5 * ( n->Z() + nSeam->Z() ));
3207               gp_XY uv;
3208               getClosestUV( projector, pMid, uv );
3209               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3210                 nodesNearSeam.insert( n );
3211                 nbUseMap2++;
3212               }
3213               else
3214                 nbUseMap1++;
3215             }
3216             // for centroidalSmooth all element nodes must
3217             // be on one side of a seam
3218             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3219               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3220               nn = 0;
3221               while ( nn++ < nbn ) {
3222                 const SMDS_MeshNode* n =
3223                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3224                 setMovableNodes.erase( n );
3225               }
3226             }
3227           }
3228         } // loop on nodes on seam
3229       } // loop on edge of a face
3230     } // if ( !face.IsNull() )
3231
3232     if ( setMovableNodes.empty() ) {
3233       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3234       continue; // goto next face
3235     }
3236
3237     // -------------
3238     // SMOOTHING //
3239     // -------------
3240
3241     int it = -1;
3242     double maxRatio = -1., maxDisplacement = -1.;
3243     set<const SMDS_MeshNode*>::iterator nodeToMove;
3244     for ( it = 0; it < theNbIterations; it++ ) {
3245       maxDisplacement = 0.;
3246       nodeToMove = setMovableNodes.begin();
3247       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3248         const SMDS_MeshNode* node = (*nodeToMove);
3249         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3250
3251         // smooth
3252         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3253         if ( theSmoothMethod == LAPLACIAN )
3254           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3255         else
3256           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3257
3258         // node displacement
3259         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3260         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3261         if ( aDispl > maxDisplacement )
3262           maxDisplacement = aDispl;
3263       }
3264       // no node movement => exit
3265       //if ( maxDisplacement < 1.e-16 ) {
3266       if ( maxDisplacement < disttol ) {
3267         MESSAGE("-- no node movement --");
3268         break;
3269       }
3270
3271       // check elements quality
3272       maxRatio  = 0;
3273       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3274       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3275         const SMDS_MeshElement* elem = (*elemIt);
3276         if ( !elem || elem->GetType() != SMDSAbs_Face )
3277           continue;
3278         SMESH::Controls::TSequenceOfXYZ aPoints;
3279         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3280           double aValue = aQualityFunc.GetValue( aPoints );
3281           if ( aValue > maxRatio )
3282             maxRatio = aValue;
3283         }
3284       }
3285       if ( maxRatio <= theTgtAspectRatio ) {
3286         MESSAGE("-- quality achived --");
3287         break;
3288       }
3289       if (it+1 == theNbIterations) {
3290         MESSAGE("-- Iteration limit exceeded --");
3291       }
3292     } // smoothing iterations
3293
3294     MESSAGE(" Face id: " << *fId <<
3295             " Nb iterstions: " << it <<
3296             " Displacement: " << maxDisplacement <<
3297             " Aspect Ratio " << maxRatio);
3298
3299     // ---------------------------------------
3300     // new nodes positions are computed,
3301     // record movement in DS and set new UV
3302     // ---------------------------------------
3303     nodeToMove = setMovableNodes.begin();
3304     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3305       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3306       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3307       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3308       if ( node_uv != uvMap.end() ) {
3309         gp_XY* uv = node_uv->second;
3310         node->SetPosition
3311           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3312       }
3313     }
3314
3315     // move medium nodes of quadratic elements
3316     if ( isQuadratic )
3317     {
3318       SMESH_MesherHelper helper( *GetMesh() );
3319       if ( !face.IsNull() )
3320         helper.SetSubShape( face );
3321       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3322       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3323         const SMDS_VtkFace* QF =
3324           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3325         if(QF && QF->IsQuadratic()) {
3326           vector<const SMDS_MeshNode*> Ns;
3327           Ns.reserve(QF->NbNodes()+1);
3328           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3329           while ( anIter->more() )
3330             Ns.push_back( cast2Node(anIter->next()) );
3331           Ns.push_back( Ns[0] );
3332           double x, y, z;
3333           for(int i=0; i<QF->NbNodes(); i=i+2) {
3334             if ( !surface.IsNull() ) {
3335               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3336               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3337               gp_XY uv = ( uv1 + uv2 ) / 2.;
3338               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3339               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3340             }
3341             else {
3342               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3343               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3344               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3345             }
3346             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3347                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3348                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3349               // we have to move i+1 node
3350               aMesh->MoveNode( Ns[i+1], x, y, z );
3351             }
3352           }
3353         }
3354       }
3355     }
3356
3357   } // loop on face ids
3358
3359 }
3360
3361 //=======================================================================
3362 //function : isReverse
3363 //purpose  : Return true if normal of prevNodes is not co-directied with
3364 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3365 //           iNotSame is where prevNodes and nextNodes are different
3366 //=======================================================================
3367
3368 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3369                       vector<const SMDS_MeshNode*> nextNodes,
3370                       const int            nbNodes,
3371                       const int            iNotSame)
3372 {
3373   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3374   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3375
3376   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3377   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3378   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3379   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3380
3381   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3382   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3383   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3384   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3385
3386   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3387
3388   return (vA ^ vB) * vN < 0.0;
3389 }
3390
3391 //=======================================================================
3392 /*!
3393  * \brief Create elements by sweeping an element
3394  * \param elem - element to sweep
3395  * \param newNodesItVec - nodes generated from each node of the element
3396  * \param newElems - generated elements
3397  * \param nbSteps - number of sweeping steps
3398  * \param srcElements - to append elem for each generated element
3399  */
3400 //=======================================================================
3401
3402 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3403                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3404                                     list<const SMDS_MeshElement*>&        newElems,
3405                                     const int                             nbSteps,
3406                                     SMESH_SequenceOfElemPtr&              srcElements)
3407 {
3408   //MESSAGE("sweepElement " << nbSteps);
3409   SMESHDS_Mesh* aMesh = GetMeshDS();
3410
3411   // Loop on elem nodes:
3412   // find new nodes and detect same nodes indices
3413   int nbNodes = elem->NbNodes();
3414   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3415   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3416   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3417   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3418
3419   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3420   vector<int> sames(nbNodes);
3421   vector<bool> issimple(nbNodes);
3422
3423   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3424     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3425     const SMDS_MeshNode*                 node         = nnIt->first;
3426     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3427     if ( listNewNodes.empty() ) {
3428       return;
3429     }
3430
3431     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3432
3433     itNN[ iNode ] = listNewNodes.begin();
3434     prevNod[ iNode ] = node;
3435     nextNod[ iNode ] = listNewNodes.front();
3436     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3437       if ( prevNod[ iNode ] != nextNod [ iNode ])
3438         iNotSameNode = iNode;
3439       else {
3440         iSameNode = iNode;
3441         //nbSame++;
3442         sames[nbSame++] = iNode;
3443       }
3444     }
3445   }
3446
3447   //cerr<<"  nbSame = "<<nbSame<<endl;
3448   if ( nbSame == nbNodes || nbSame > 2) {
3449     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3450     //INFOS( " Too many same nodes of element " << elem->GetID() );
3451     return;
3452   }
3453
3454   //  if( elem->IsQuadratic() && nbSame>0 ) {
3455   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3456   //    return;
3457   //  }
3458
3459   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3460   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3461   if ( nbSame > 0 ) {
3462     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3463     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3464     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3465   }
3466
3467   //if(nbNodes==8)
3468   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3469   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3470   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3471   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3472
3473   // check element orientation
3474   int i0 = 0, i2 = 2;
3475   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3476     //MESSAGE("Reversed elem " << elem );
3477     i0 = 2;
3478     i2 = 0;
3479     if ( nbSame > 0 )
3480       std::swap( iBeforeSame, iAfterSame );
3481   }
3482
3483   // make new elements
3484   const SMDS_MeshElement* lastElem = elem;
3485   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3486     // get next nodes
3487     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3488       if(issimple[iNode]) {
3489         nextNod[ iNode ] = *itNN[ iNode ];
3490         itNN[ iNode ]++;
3491       }
3492       else {
3493         if( elem->GetType()==SMDSAbs_Node ) {
3494           // we have to use two nodes
3495           midlNod[ iNode ] = *itNN[ iNode ];
3496           itNN[ iNode ]++;
3497           nextNod[ iNode ] = *itNN[ iNode ];
3498           itNN[ iNode ]++;
3499         }
3500         else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3501           // we have to use each second node
3502           //itNN[ iNode ]++;
3503           nextNod[ iNode ] = *itNN[ iNode ];
3504           itNN[ iNode ]++;
3505         }
3506         else {
3507           // we have to use two nodes
3508           midlNod[ iNode ] = *itNN[ iNode ];
3509           itNN[ iNode ]++;
3510           nextNod[ iNode ] = *itNN[ iNode ];
3511           itNN[ iNode ]++;
3512         }
3513       }
3514     }
3515     SMDS_MeshElement* aNewElem = 0;
3516     if(!elem->IsPoly()) {
3517       switch ( nbNodes ) {
3518       case 0:
3519         return;
3520       case 1: { // NODE
3521         if ( nbSame == 0 ) {
3522           if(issimple[0])
3523             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3524           else
3525             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3526         }
3527         break;
3528       }
3529       case 2: { // EDGE
3530         if ( nbSame == 0 )
3531           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3532                                     nextNod[ 1 ], nextNod[ 0 ] );
3533         else
3534           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3535                                     nextNod[ iNotSameNode ] );
3536         break;
3537       }
3538
3539       case 3: { // TRIANGLE or quadratic edge
3540         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3541
3542           if ( nbSame == 0 )       // --- pentahedron
3543             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3544                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3545
3546           else if ( nbSame == 1 )  // --- pyramid
3547             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3548                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3549                                          nextNod[ iSameNode ]);
3550
3551           else // 2 same nodes:      --- tetrahedron
3552             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3553                                          nextNod[ iNotSameNode ]);
3554         }
3555         else { // quadratic edge
3556           if(nbSame==0) {     // quadratic quadrangle
3557             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3558                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3559           }
3560           else if(nbSame==1) { // quadratic triangle
3561             if(sames[0]==2) {
3562               return; // medium node on axis
3563             }
3564             else if(sames[0]==0) {
3565               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3566                                         nextNod[2], midlNod[1], prevNod[2]);
3567             }
3568             else { // sames[0]==1
3569               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3570                                         midlNod[0], nextNod[2], prevNod[2]);
3571             }
3572           }
3573           else {
3574             return;
3575           }
3576         }
3577         break;
3578       }
3579       case 4: { // QUADRANGLE
3580
3581         if ( nbSame == 0 )       // --- hexahedron
3582           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3583                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3584
3585         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3586           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3587                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3588                                        nextNod[ iSameNode ]);
3589           newElems.push_back( aNewElem );
3590           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3591                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3592                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3593         }
3594         else if ( nbSame == 2 ) { // pentahedron
3595           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3596             // iBeforeSame is same too
3597             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3598                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3599                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3600           else
3601             // iAfterSame is same too
3602             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3603                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3604                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3605         }
3606         break;
3607       }
3608       case 6: { // quadratic triangle
3609         // create pentahedron with 15 nodes
3610         if(nbSame==0) {
3611           if(i0>0) { // reversed case
3612             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3613                                          nextNod[0], nextNod[2], nextNod[1],
3614                                          prevNod[5], prevNod[4], prevNod[3],
3615                                          nextNod[5], nextNod[4], nextNod[3],
3616                                          midlNod[0], midlNod[2], midlNod[1]);
3617           }
3618           else { // not reversed case
3619             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3620                                          nextNod[0], nextNod[1], nextNod[2],
3621                                          prevNod[3], prevNod[4], prevNod[5],
3622                                          nextNod[3], nextNod[4], nextNod[5],
3623                                          midlNod[0], midlNod[1], midlNod[2]);
3624           }
3625         }
3626         else if(nbSame==1) {
3627           // 2d order pyramid of 13 nodes
3628           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3629           //                                 int n12,int n23,int n34,int n41,
3630           //                                 int n15,int n25,int n35,int n45, int ID);
3631           int n5 = iSameNode;
3632           int n1,n4,n41,n15,n45;
3633           if(i0>0) { // reversed case
3634             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3635             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3636             n41 = n1 + 3;
3637             n15 = n5 + 3;
3638             n45 = n4 + 3;
3639           }
3640           else {
3641             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3642             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3643             n41 = n4 + 3;
3644             n15 = n1 + 3;
3645             n45 = n5 + 3;
3646           }
3647           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3648                                       nextNod[n4], prevNod[n4], prevNod[n5],
3649                                       midlNod[n1], nextNod[n41],
3650                                       midlNod[n4], prevNod[n41],
3651                                       prevNod[n15], nextNod[n15],
3652                                       nextNod[n45], prevNod[n45]);
3653         }
3654         else if(nbSame==2) {
3655           // 2d order tetrahedron of 10 nodes
3656           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3657           //                                 int n12,int n23,int n31,
3658           //                                 int n14,int n24,int n34, int ID);
3659           int n1 = iNotSameNode;
3660           int n2,n3,n12,n23,n31;
3661           if(i0>0) { // reversed case
3662             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3663             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3664             n12 = n2 + 3;
3665             n23 = n3 + 3;
3666             n31 = n1 + 3;
3667           }
3668           else {
3669             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3670             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3671             n12 = n1 + 3;
3672             n23 = n2 + 3;
3673             n31 = n3 + 3;
3674           }
3675           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3676                                        prevNod[n12], prevNod[n23], prevNod[n31],
3677                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3678         }
3679         break;
3680       }
3681       case 8: { // quadratic quadrangle
3682         if(nbSame==0) {
3683           // create hexahedron with 20 nodes
3684           if(i0>0) { // reversed case
3685             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3686                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3687                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3688                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3689                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3690           }
3691           else { // not reversed case
3692             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3693                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3694                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3695                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3696                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3697           }
3698         }
3699         else if(nbSame==1) { 
3700           // --- pyramid + pentahedron - can not be created since it is needed 
3701           // additional middle node ot the center of face
3702           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3703           return;
3704         }
3705         else if(nbSame==2) {
3706           // 2d order Pentahedron with 15 nodes
3707           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3708           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3709           //                                 int n14,int n25,int n36, int ID);
3710           int n1,n2,n4,n5;
3711           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3712             // iBeforeSame is same too
3713             n1 = iBeforeSame;
3714             n2 = iOpposSame;
3715             n4 = iSameNode;
3716             n5 = iAfterSame;
3717           }
3718           else {
3719             // iAfterSame is same too
3720             n1 = iSameNode;
3721             n2 = iBeforeSame;
3722             n4 = iAfterSame;
3723             n5 = iOpposSame;
3724           }
3725           int n12,n45,n14,n25;
3726           if(i0>0) { //reversed case
3727             n12 = n1 + 4;
3728             n45 = n5 + 4;
3729             n14 = n4 + 4;
3730             n25 = n2 + 4;
3731           }
3732           else {
3733             n12 = n2 + 4;
3734             n45 = n4 + 4;
3735             n14 = n1 + 4;
3736             n25 = n5 + 4;
3737           }
3738           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3739                                        prevNod[n4], prevNod[n5], nextNod[n5],
3740                                        prevNod[n12], midlNod[n2], nextNod[n12],
3741                                        prevNod[n45], midlNod[n5], nextNod[n45],
3742                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3743         }
3744         break;
3745       }
3746       default: {
3747         // realized for extrusion only
3748         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3749         //vector<int> quantities (nbNodes + 2);
3750
3751         //quantities[0] = nbNodes; // bottom of prism
3752         //for (int inode = 0; inode < nbNodes; inode++) {
3753         //  polyedre_nodes[inode] = prevNod[inode];
3754         //}
3755
3756         //quantities[1] = nbNodes; // top of prism
3757         //for (int inode = 0; inode < nbNodes; inode++) {
3758         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3759         //}
3760
3761         //for (int iface = 0; iface < nbNodes; iface++) {
3762         //  quantities[iface + 2] = 4;
3763         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3764         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3765         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3766         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3767         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3768         //}
3769         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3770         break;
3771       }
3772       }
3773     }
3774
3775     if(!aNewElem) {
3776       // realized for extrusion only
3777       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3778       vector<int> quantities (nbNodes + 2);
3779
3780       quantities[0] = nbNodes; // bottom of prism
3781       for (int inode = 0; inode < nbNodes; inode++) {
3782         polyedre_nodes[inode] = prevNod[inode];
3783       }
3784
3785       quantities[1] = nbNodes; // top of prism
3786       for (int inode = 0; inode < nbNodes; inode++) {
3787         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3788       }
3789
3790       for (int iface = 0; iface < nbNodes; iface++) {
3791         quantities[iface + 2] = 4;
3792         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3793         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3794         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3795         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3796         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3797       }
3798       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3799     }
3800
3801     if ( aNewElem ) {
3802       newElems.push_back( aNewElem );
3803       myLastCreatedElems.Append(aNewElem);
3804       srcElements.Append( elem );
3805       lastElem = aNewElem;
3806     }
3807
3808     // set new prev nodes
3809     for ( iNode = 0; iNode < nbNodes; iNode++ )
3810       prevNod[ iNode ] = nextNod[ iNode ];
3811
3812   } // for steps
3813 }
3814
3815 //=======================================================================
3816 /*!
3817  * \brief Create 1D and 2D elements around swept elements
3818  * \param mapNewNodes - source nodes and ones generated from them
3819  * \param newElemsMap - source elements and ones generated from them
3820  * \param elemNewNodesMap - nodes generated from each node of each element
3821  * \param elemSet - all swept elements
3822  * \param nbSteps - number of sweeping steps
3823  * \param srcElements - to append elem for each generated element
3824  */
3825 //=======================================================================
3826
3827 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3828                                   TElemOfElemListMap &     newElemsMap,
3829                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3830                                   TIDSortedElemSet&        elemSet,
3831                                   const int                nbSteps,
3832                                   SMESH_SequenceOfElemPtr& srcElements)
3833 {
3834   MESSAGE("makeWalls");
3835   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3836   SMESHDS_Mesh* aMesh = GetMeshDS();
3837
3838   // Find nodes belonging to only one initial element - sweep them to get edges.
3839
3840   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3841   for ( ; nList != mapNewNodes.end(); nList++ ) {
3842     const SMDS_MeshNode* node =
3843       static_cast<const SMDS_MeshNode*>( nList->first );
3844     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3845     int nbInitElems = 0;
3846     const SMDS_MeshElement* el = 0;
3847     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3848     while ( eIt->more() && nbInitElems < 2 ) {
3849       el = eIt->next();
3850       SMDSAbs_ElementType type = el->GetType();
3851       if ( type == SMDSAbs_Volume || type < highType ) continue;
3852       if ( type > highType ) {
3853         nbInitElems = 0;
3854         highType = type;
3855       }
3856       if ( elemSet.find(el) != elemSet.end() )
3857         nbInitElems++;
3858     }
3859     if ( nbInitElems < 2 ) {
3860       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3861       if(!NotCreateEdge) {
3862         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3863         list<const SMDS_MeshElement*> newEdges;
3864         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3865       }
3866     }
3867   }
3868
3869   // Make a ceiling for each element ie an equal element of last new nodes.
3870   // Find free links of faces - make edges and sweep them into faces.
3871
3872   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3873   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3874   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3875     const SMDS_MeshElement* elem = itElem->first;
3876     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3877
3878     if(itElem->second.size()==0) continue;
3879
3880     if ( elem->GetType() == SMDSAbs_Edge ) {
3881       // create a ceiling edge
3882       if (!elem->IsQuadratic()) {
3883         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3884                                vecNewNodes[ 1 ]->second.back())) {
3885           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3886                                                    vecNewNodes[ 1 ]->second.back()));
3887           srcElements.Append( myLastCreatedElems.Last() );
3888         }
3889       }
3890       else {
3891         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3892                                vecNewNodes[ 1 ]->second.back(),
3893                                vecNewNodes[ 2 ]->second.back())) {
3894           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3895                                                    vecNewNodes[ 1 ]->second.back(),
3896                                                    vecNewNodes[ 2 ]->second.back()));
3897           srcElements.Append( myLastCreatedElems.Last() );
3898         }
3899       }
3900     }
3901     if ( elem->GetType() != SMDSAbs_Face )
3902       continue;
3903
3904     bool hasFreeLinks = false;
3905
3906     TIDSortedElemSet avoidSet;
3907     avoidSet.insert( elem );
3908
3909     set<const SMDS_MeshNode*> aFaceLastNodes;
3910     int iNode, nbNodes = vecNewNodes.size();
3911     if(!elem->IsQuadratic()) {
3912       // loop on the face nodes
3913       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3914         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3915         // look for free links of the face
3916         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3917         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3918         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3919         // check if a link is free
3920         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3921           hasFreeLinks = true;
3922           // make an edge and a ceiling for a new edge
3923           if ( !aMesh->FindEdge( n1, n2 )) {
3924             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3925             srcElements.Append( myLastCreatedElems.Last() );
3926           }
3927           n1 = vecNewNodes[ iNode ]->second.back();
3928           n2 = vecNewNodes[ iNext ]->second.back();
3929           if ( !aMesh->FindEdge( n1, n2 )) {
3930             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3931             srcElements.Append( myLastCreatedElems.Last() );
3932           }
3933         }
3934       }
3935     }
3936     else { // elem is quadratic face
3937       int nbn = nbNodes/2;
3938       for ( iNode = 0; iNode < nbn; iNode++ ) {
3939         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3940         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3941         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3942         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3943         // check if a link is free
3944         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3945           hasFreeLinks = true;
3946           // make an edge and a ceiling for a new edge
3947           // find medium node
3948           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3949           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3950             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3951             srcElements.Append( myLastCreatedElems.Last() );
3952           }
3953           n1 = vecNewNodes[ iNode ]->second.back();
3954           n2 = vecNewNodes[ iNext ]->second.back();
3955           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3956           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3957             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3958             srcElements.Append( myLastCreatedElems.Last() );
3959           }
3960         }
3961       }
3962       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3963         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3964       }
3965     }
3966
3967     // sweep free links into faces
3968
3969     if ( hasFreeLinks )  {
3970       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3971       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3972
3973       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3974       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3975         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3976         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3977       }
3978       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3979         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3980         iVol = 0;
3981         while ( iVol++ < volNb ) v++;
3982         // find indices of free faces of a volume and their source edges
3983         list< int > freeInd;
3984         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3985         SMDS_VolumeTool vTool( *v );
3986         int iF, nbF = vTool.NbFaces();
3987         for ( iF = 0; iF < nbF; iF ++ ) {
3988           if (vTool.IsFreeFace( iF ) &&
3989               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3990               initNodeSet != faceNodeSet) // except an initial face
3991           {
3992             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3993               continue;
3994             freeInd.push_back( iF );
3995             // find source edge of a free face iF
3996             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3997             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3998             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3999                                    initNodeSet.begin(), initNodeSet.end(),
4000                                    commonNodes.begin());
4001             if ( (*v)->IsQuadratic() )
4002               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4003             else
4004               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4005 #ifdef _DEBUG_
4006             if ( !srcEdges.back() )
4007             {
4008               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4009                    << iF << " of volume #" << vTool.ID() << endl;
4010             }
4011 #endif
4012           }
4013         }
4014         if ( freeInd.empty() )
4015           continue;
4016
4017         // create faces for all steps;
4018         // if such a face has been already created by sweep of edge,
4019         // assure that its orientation is OK
4020         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
4021           vTool.Set( *v );
4022           vTool.SetExternalNormal();
4023           const int nextShift = vTool.IsForward() ? +1 : -1;
4024           list< int >::iterator ind = freeInd.begin();
4025           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4026           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4027           {
4028             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4029             int nbn = vTool.NbFaceNodes( *ind );
4030             if ( ! (*v)->IsPoly() )
4031               switch ( nbn ) {
4032               case 3: { ///// triangle
4033                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4034                 if ( !f ||
4035                      nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4036                 {
4037                   const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4038                                                        nodes[ 1 ],
4039                                                        nodes[ 1 + nextShift ] };
4040                   if ( f )
4041                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4042                   else
4043                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4044                                                               newOrder[ 2 ] ));
4045                 }
4046                 break;
4047               }
4048               case 4: { ///// quadrangle
4049                 const SMDS_MeshFace * f =
4050                   aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4051                 if ( !f ||
4052                      nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4053                 {
4054                   const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4055                                                        nodes[ 2 ], nodes[ 2+nextShift ] };
4056                   if ( f )
4057                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4058                   else
4059                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4060                                                               newOrder[ 2 ], newOrder[ 3 ]));
4061                 }
4062                 break;
4063               }
4064               case 6: { /////// quadratic triangle
4065                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4066                                                            nodes[1], nodes[3], nodes[5] );
4067                 if ( !f ||
4068                      nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4069                 {
4070                   const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4071                                                        nodes[2],
4072                                                        nodes[2 + 2*nextShift],
4073                                                        nodes[3 - 2*nextShift],
4074                                                        nodes[3],
4075                                                        nodes[3 + 2*nextShift]};
4076                   if ( f )
4077                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4078                   else
4079                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4080                                                               newOrder[ 1 ],
4081                                                               newOrder[ 2 ],
4082                                                               newOrder[ 3 ],
4083                                                               newOrder[ 4 ],
4084                                                               newOrder[ 5 ] ));
4085                 }
4086                 break;
4087               }
4088               default:       /////// quadratic quadrangle
4089                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4090                                                            nodes[1], nodes[3], nodes[5], nodes[7] );
4091                 if ( !f ||
4092                      nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4093                 {
4094                   const SMDS_MeshNode* newOrder[8] = { nodes[0],
4095                                                        nodes[4 - 2*nextShift],
4096                                                        nodes[4],
4097                                                        nodes[4 + 2*nextShift],
4098                                                        nodes[1],
4099                                                        nodes[5 - 2*nextShift],
4100                                                        nodes[5],
4101                                                        nodes[5 + 2*nextShift] };
4102                   if ( f )
4103                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4104                   else
4105                     myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4106                                                              newOrder[ 2 ], newOrder[ 3 ],
4107                                                              newOrder[ 4 ], newOrder[ 5 ],
4108                                                              newOrder[ 6 ], newOrder[ 7 ]));
4109                 }
4110               } // switch ( nbn )
4111
4112             else { //////// polygon
4113
4114               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4115               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4116               if ( !f ||
4117                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4118               {
4119                 if ( !vTool.IsForward() )
4120                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4121                 if ( f )
4122                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4123                 else
4124                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4125               }
4126             }
4127
4128             while ( srcElements.Length() < myLastCreatedElems.Length() )
4129               srcElements.Append( *srcEdge );
4130
4131           }  // loop on free faces
4132
4133           // go to the next volume
4134           iVol = 0;
4135           while ( iVol++ < nbVolumesByStep ) v++;
4136
4137         } // loop on steps
4138       } // loop on volumes of one step
4139     } // sweep free links into faces
4140
4141     // Make a ceiling face with a normal external to a volume
4142
4143     SMDS_VolumeTool lastVol( itElem->second.back() );
4144
4145     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4146     if ( iF >= 0 ) {
4147       lastVol.SetExternalNormal();
4148       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4149       int nbn = lastVol.NbFaceNodes( iF );
4150       switch ( nbn ) {
4151       case 3:
4152         if (!hasFreeLinks ||
4153             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4154           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4155         break;
4156       case 4:
4157         if (!hasFreeLinks ||
4158             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4159           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4160         break;
4161       default:
4162         if(itElem->second.back()->IsQuadratic()) {
4163           if(nbn==6) {
4164             if (!hasFreeLinks ||
4165                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4166                                  nodes[1], nodes[3], nodes[5]) ) {
4167               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4168                                                        nodes[1], nodes[3], nodes[5]));
4169             }
4170           }
4171           else { // nbn==8
4172             if (!hasFreeLinks ||
4173                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4174                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4175               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4176                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4177           }
4178         }
4179         else {
4180           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4181           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4182             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4183         }
4184       } // switch
4185
4186       while ( srcElements.Length() < myLastCreatedElems.Length() )
4187         srcElements.Append( myLastCreatedElems.Last() );
4188     }
4189   } // loop on swept elements
4190 }
4191
4192 //=======================================================================
4193 //function : RotationSweep
4194 //purpose  :
4195 //=======================================================================
4196
4197 SMESH_MeshEditor::PGroupIDs
4198 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4199                                 const gp_Ax1&      theAxis,
4200                                 const double       theAngle,
4201                                 const int          theNbSteps,
4202                                 const double       theTol,
4203                                 const bool         theMakeGroups,
4204                                 const bool         theMakeWalls)
4205 {
4206   myLastCreatedElems.Clear();
4207   myLastCreatedNodes.Clear();
4208
4209   // source elements for each generated one
4210   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4211
4212   MESSAGE( "RotationSweep()");
4213   gp_Trsf aTrsf;
4214   aTrsf.SetRotation( theAxis, theAngle );
4215   gp_Trsf aTrsf2;
4216   aTrsf2.SetRotation( theAxis, theAngle/2. );
4217
4218   gp_Lin aLine( theAxis );
4219   double aSqTol = theTol * theTol;
4220
4221   SMESHDS_Mesh* aMesh = GetMeshDS();
4222
4223   TNodeOfNodeListMap mapNewNodes;
4224   TElemOfVecOfNnlmiMap mapElemNewNodes;
4225   TElemOfElemListMap newElemsMap;
4226
4227   // loop on theElems
4228   TIDSortedElemSet::iterator itElem;
4229   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4230     const SMDS_MeshElement* elem = *itElem;
4231     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4232       continue;
4233     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4234     newNodesItVec.reserve( elem->NbNodes() );
4235
4236     // loop on elem nodes
4237     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4238     while ( itN->more() ) {
4239       // check if a node has been already sweeped
4240       const SMDS_MeshNode* node = cast2Node( itN->next() );
4241
4242       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4243       double coord[3];
4244       aXYZ.Coord( coord[0], coord[1], coord[2] );
4245       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4246
4247       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4248       if ( nIt == mapNewNodes.end() ) {
4249         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4250         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4251
4252         // make new nodes
4253         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4254         //double coord[3];
4255         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4256         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4257         const SMDS_MeshNode * newNode = node;
4258         for ( int i = 0; i < theNbSteps; i++ ) {
4259           if ( !isOnAxis ) {
4260             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4261               // create two nodes
4262               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4263               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4264               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4265               myLastCreatedNodes.Append(newNode);
4266               srcNodes.Append( node );
4267               listNewNodes.push_back( newNode );
4268               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4269               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4270             }
4271             else {
4272               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4273             }
4274             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4275             myLastCreatedNodes.Append(newNode);
4276             srcNodes.Append( node );
4277             listNewNodes.push_back( newNode );
4278           }
4279           else {
4280             listNewNodes.push_back( newNode );
4281             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4282               listNewNodes.push_back( newNode );
4283             }
4284           }
4285         }
4286       }
4287       /*
4288         else {
4289         // if current elem is quadratic and current node is not medium
4290         // we have to check - may be it is needed to insert additional nodes
4291         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4292         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4293         if(listNewNodes.size()==theNbSteps) {
4294         listNewNodes.clear();
4295         // make new nodes
4296         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4297         //double coord[3];
4298         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4299         const SMDS_MeshNode * newNode = node;
4300         if ( !isOnAxis ) {
4301         for(int i = 0; i<theNbSteps; i++) {
4302         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4303         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4304         cout<<"    3 AddNode:  "<<newNode;
4305         myLastCreatedNodes.Append(newNode);
4306         listNewNodes.push_back( newNode );
4307         srcNodes.Append( node );
4308         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4309         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4310         cout<<"    4 AddNode:  "<<newNode;
4311         myLastCreatedNodes.Append(newNode);
4312         srcNodes.Append( node );
4313         listNewNodes.push_back( newNode );
4314         }
4315         }
4316         else {
4317         listNewNodes.push_back( newNode );
4318         }
4319         }
4320         }
4321         }
4322       */
4323       newNodesItVec.push_back( nIt );
4324     }
4325     // make new elements
4326     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4327   }
4328
4329   if ( theMakeWalls )
4330     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4331
4332   PGroupIDs newGroupIDs;
4333   if ( theMakeGroups )
4334     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4335
4336   return newGroupIDs;
4337 }
4338
4339
4340 //=======================================================================
4341 //function : CreateNode
4342 //purpose  :
4343 //=======================================================================
4344 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4345                                                   const double y,
4346                                                   const double z,
4347                                                   const double tolnode,
4348                                                   SMESH_SequenceOfNode& aNodes)
4349 {
4350   myLastCreatedElems.Clear();
4351   myLastCreatedNodes.Clear();
4352
4353   gp_Pnt P1(x,y,z);
4354   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4355
4356   // try to search in sequence of existing nodes
4357   // if aNodes.Length()>0 we 'nave to use given sequence
4358   // else - use all nodes of mesh
4359   if(aNodes.Length()>0) {
4360     int i;
4361     for(i=1; i<=aNodes.Length(); i++) {
4362       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4363       if(P1.Distance(P2)<tolnode)
4364         return aNodes.Value(i);
4365     }
4366   }
4367   else {
4368     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4369     while(itn->more()) {
4370       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4371       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4372       if(P1.Distance(P2)<tolnode)
4373         return aN;
4374     }
4375   }
4376
4377   // create new node and return it
4378   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4379   myLastCreatedNodes.Append(NewNode);
4380   return NewNode;
4381 }
4382
4383
4384 //=======================================================================
4385 //function : ExtrusionSweep
4386 //purpose  :
4387 //=======================================================================
4388
4389 SMESH_MeshEditor::PGroupIDs
4390 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4391                                   const gp_Vec&       theStep,
4392                                   const int           theNbSteps,
4393                                   TElemOfElemListMap& newElemsMap,
4394                                   const bool          theMakeGroups,
4395                                   const int           theFlags,
4396                                   const double        theTolerance)
4397 {
4398   ExtrusParam aParams;
4399   aParams.myDir = gp_Dir(theStep);
4400   aParams.myNodes.Clear();
4401   aParams.mySteps = new TColStd_HSequenceOfReal;
4402   int i;
4403   for(i=1; i<=theNbSteps; i++)
4404     aParams.mySteps->Append(theStep.Magnitude());
4405
4406   return
4407     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4408 }
4409
4410
4411 //=======================================================================
4412 //function : ExtrusionSweep
4413 //purpose  :
4414 //=======================================================================
4415
4416 SMESH_MeshEditor::PGroupIDs
4417 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4418                                   ExtrusParam&        theParams,
4419                                   TElemOfElemListMap& newElemsMap,
4420                                   const bool          theMakeGroups,
4421                                   const int           theFlags,
4422                                   const double        theTolerance)
4423 {
4424   MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4425   myLastCreatedElems.Clear();
4426   myLastCreatedNodes.Clear();
4427
4428   // source elements for each generated one
4429   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4430
4431   SMESHDS_Mesh* aMesh = GetMeshDS();
4432
4433   int nbsteps = theParams.mySteps->Length();
4434
4435   TNodeOfNodeListMap mapNewNodes;
4436   //TNodeOfNodeVecMap mapNewNodes;
4437   TElemOfVecOfNnlmiMap mapElemNewNodes;
4438   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4439
4440   // loop on theElems
4441   TIDSortedElemSet::iterator itElem;
4442   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4443     // check element type
4444     const SMDS_MeshElement* elem = *itElem;
4445     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4446       continue;
4447
4448     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4449     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4450     newNodesItVec.reserve( elem->NbNodes() );
4451
4452     // loop on elem nodes
4453     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4454     while ( itN->more() )
4455     {
4456       // check if a node has been already sweeped
4457       const SMDS_MeshNode* node = cast2Node( itN->next() );
4458       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4459       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4460       if ( nIt == mapNewNodes.end() ) {
4461         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4462         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4463         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4464         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4465         //vecNewNodes.reserve(nbsteps);
4466
4467         // make new nodes
4468         double coord[] = { node->X(), node->Y(), node->Z() };
4469         //int nbsteps = theParams.mySteps->Length();
4470         for ( int i = 0; i < nbsteps; i++ ) {
4471           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4472             // create additional node
4473             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4474             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4475             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4476             if( theFlags & EXTRUSION_FLAG_SEW ) {
4477               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4478                                                          theTolerance, theParams.myNodes);
4479               listNewNodes.push_back( newNode );
4480             }
4481             else {
4482               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4483               myLastCreatedNodes.Append(newNode);
4484               srcNodes.Append( node );
4485               listNewNodes.push_back( newNode );
4486             }
4487           }
4488           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4489           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4490           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4491           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4492           if( theFlags & EXTRUSION_FLAG_SEW ) {
4493             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4494                                                        theTolerance, theParams.myNodes);
4495             listNewNodes.push_back( newNode );
4496             //vecNewNodes[i]=newNode;
4497           }
4498           else {
4499             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4500             myLastCreatedNodes.Append(newNode);
4501             srcNodes.Append( node );
4502             listNewNodes.push_back( newNode );
4503             //vecNewNodes[i]=newNode;
4504           }
4505         }
4506       }
4507       else {
4508         // if current elem is quadratic and current node is not medium
4509         // we have to check - may be it is needed to insert additional nodes
4510         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4511           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4512           if(listNewNodes.size()==nbsteps) {
4513             listNewNodes.clear();
4514             double coord[] = { node->X(), node->Y(), node->Z() };
4515             for ( int i = 0; i < nbsteps; i++ ) {
4516               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4517               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4518               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4519               if( theFlags & EXTRUSION_FLAG_SEW ) {
4520                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4521                                                            theTolerance, theParams.myNodes);
4522                 listNewNodes.push_back( newNode );
4523               }
4524               else {
4525                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4526                 myLastCreatedNodes.Append(newNode);
4527                 srcNodes.Append( node );
4528                 listNewNodes.push_back( newNode );
4529               }
4530               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4531               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4532               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4533               if( theFlags & EXTRUSION_FLAG_SEW ) {
4534                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4535                                                            theTolerance, theParams.myNodes);
4536                 listNewNodes.push_back( newNode );
4537               }
4538               else {
4539                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4540                 myLastCreatedNodes.Append(newNode);
4541                 srcNodes.Append( node );
4542                 listNewNodes.push_back( newNode );
4543               }
4544             }
4545           }
4546         }
4547       }
4548       newNodesItVec.push_back( nIt );
4549     }
4550     // make new elements
4551     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4552   }
4553
4554   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4555     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4556   }
4557   PGroupIDs newGroupIDs;
4558   if ( theMakeGroups )
4559     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4560
4561   return newGroupIDs;
4562 }
4563
4564 /*
4565 //=======================================================================
4566 //class    : SMESH_MeshEditor_PathPoint
4567 //purpose  : auxiliary class
4568 //=======================================================================
4569 class SMESH_MeshEditor_PathPoint {
4570 public:
4571 SMESH_MeshEditor_PathPoint() {
4572 myPnt.SetCoord(99., 99., 99.);
4573 myTgt.SetCoord(1.,0.,0.);
4574 myAngle=0.;
4575 myPrm=0.;
4576 }
4577 void SetPnt(const gp_Pnt& aP3D){
4578 myPnt=aP3D;
4579 }
4580 void SetTangent(const gp_Dir& aTgt){
4581 myTgt=aTgt;
4582 }
4583 void SetAngle(const double& aBeta){
4584 myAngle=aBeta;
4585 }
4586 void SetParameter(const double& aPrm){
4587 myPrm=aPrm;
4588 }
4589 const gp_Pnt& Pnt()const{
4590 return myPnt;
4591 }
4592 const gp_Dir& Tangent()const{
4593 return myTgt;
4594 }
4595 double Angle()const{
4596 return myAngle;
4597 }
4598 double Parameter()const{
4599 return myPrm;
4600 }
4601
4602 protected:
4603 gp_Pnt myPnt;
4604 gp_Dir myTgt;
4605 double myAngle;
4606 double myPrm;
4607 };
4608 */
4609
4610 //=======================================================================
4611 //function : ExtrusionAlongTrack
4612 //purpose  :
4613 //=======================================================================
4614 SMESH_MeshEditor::Extrusion_Error
4615 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4616                                        SMESH_subMesh*       theTrack,
4617                                        const SMDS_MeshNode* theN1,
4618                                        const bool           theHasAngles,
4619                                        list<double>&        theAngles,
4620                                        const bool           theLinearVariation,
4621                                        const bool           theHasRefPoint,
4622                                        const gp_Pnt&        theRefPoint,
4623                                        const bool           theMakeGroups)
4624 {
4625   MESSAGE("ExtrusionAlongTrack");
4626   myLastCreatedElems.Clear();
4627   myLastCreatedNodes.Clear();
4628
4629   int aNbE;
4630   std::list<double> aPrms;
4631   TIDSortedElemSet::iterator itElem;
4632
4633   gp_XYZ aGC;
4634   TopoDS_Edge aTrackEdge;
4635   TopoDS_Vertex aV1, aV2;
4636
4637   SMDS_ElemIteratorPtr aItE;
4638   SMDS_NodeIteratorPtr aItN;
4639   SMDSAbs_ElementType aTypeE;
4640
4641   TNodeOfNodeListMap mapNewNodes;
4642
4643   // 1. Check data
4644   aNbE = theElements.size();
4645   // nothing to do
4646   if ( !aNbE )
4647     return EXTR_NO_ELEMENTS;
4648
4649   // 1.1 Track Pattern
4650   ASSERT( theTrack );
4651
4652   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4653
4654   aItE = pSubMeshDS->GetElements();
4655   while ( aItE->more() ) {
4656     const SMDS_MeshElement* pE = aItE->next();
4657     aTypeE = pE->GetType();
4658     // Pattern must contain links only
4659     if ( aTypeE != SMDSAbs_Edge )
4660       return EXTR_PATH_NOT_EDGE;
4661   }
4662
4663   list<SMESH_MeshEditor_PathPoint> fullList;
4664
4665   const TopoDS_Shape& aS = theTrack->GetSubShape();
4666   // Sub shape for the Pattern must be an Edge or Wire
4667   if( aS.ShapeType() == TopAbs_EDGE ) {
4668     aTrackEdge = TopoDS::Edge( aS );
4669     // the Edge must not be degenerated
4670     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4671       return EXTR_BAD_PATH_SHAPE;
4672     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4673     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4674     const SMDS_MeshNode* aN1 = aItN->next();
4675     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4676     const SMDS_MeshNode* aN2 = aItN->next();
4677     // starting node must be aN1 or aN2
4678     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4679       return EXTR_BAD_STARTING_NODE;
4680     aItN = pSubMeshDS->GetNodes();
4681     while ( aItN->more() ) {
4682       const SMDS_MeshNode* pNode = aItN->next();
4683       const SMDS_EdgePosition* pEPos =
4684         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4685       double aT = pEPos->GetUParameter();
4686       aPrms.push_back( aT );
4687     }
4688     //Extrusion_Error err =
4689     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4690   }
4691   else if( aS.ShapeType() == TopAbs_WIRE ) {
4692     list< SMESH_subMesh* > LSM;
4693     TopTools_SequenceOfShape Edges;
4694     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4695     while(itSM->more()) {
4696       SMESH_subMesh* SM = itSM->next();
4697       LSM.push_back(SM);
4698       const TopoDS_Shape& aS = SM->GetSubShape();
4699       Edges.Append(aS);
4700     }
4701     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4702     int startNid = theN1->GetID();
4703     TColStd_MapOfInteger UsedNums;
4704     int NbEdges = Edges.Length();
4705     int i = 1;
4706     for(; i<=NbEdges; i++) {
4707       int k = 0;
4708       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4709       for(; itLSM!=LSM.end(); itLSM++) {
4710         k++;
4711         if(UsedNums.Contains(k)) continue;
4712         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4713         SMESH_subMesh* locTrack = *itLSM;
4714         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4715         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4716         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4717         const SMDS_MeshNode* aN1 = aItN->next();
4718         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4719         const SMDS_MeshNode* aN2 = aItN->next();
4720         // starting node must be aN1 or aN2
4721         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4722         // 2. Collect parameters on the track edge
4723         aPrms.clear();
4724         aItN = locMeshDS->GetNodes();
4725         while ( aItN->more() ) {
4726           const SMDS_MeshNode* pNode = aItN->next();
4727           const SMDS_EdgePosition* pEPos =
4728             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4729           double aT = pEPos->GetUParameter();
4730           aPrms.push_back( aT );
4731         }
4732         list<SMESH_MeshEditor_PathPoint> LPP;
4733         //Extrusion_Error err =
4734         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4735         LLPPs.push_back(LPP);
4736         UsedNums.Add(k);
4737         // update startN for search following egde
4738         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4739         else startNid = aN1->GetID();
4740         break;
4741       }
4742     }
4743     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4744     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4745     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4746     for(; itPP!=firstList.end(); itPP++) {
4747       fullList.push_back( *itPP );
4748     }
4749     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4750     fullList.pop_back();
4751     itLLPP++;
4752     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4753       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4754       itPP = currList.begin();
4755       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4756       gp_Dir D1 = PP1.Tangent();
4757       gp_Dir D2 = PP2.Tangent();
4758       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4759                            (D1.Z()+D2.Z())/2 ) );
4760       PP1.SetTangent(Dnew);
4761       fullList.push_back(PP1);
4762       itPP++;
4763       for(; itPP!=firstList.end(); itPP++) {
4764         fullList.push_back( *itPP );
4765       }
4766       PP1 = fullList.back();
4767       fullList.pop_back();
4768     }
4769     // if wire not closed
4770     fullList.push_back(PP1);
4771     // else ???
4772   }
4773   else {
4774     return EXTR_BAD_PATH_SHAPE;
4775   }
4776
4777   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4778                           theHasRefPoint, theRefPoint, theMakeGroups);
4779 }
4780
4781
4782 //=======================================================================
4783 //function : ExtrusionAlongTrack
4784 //purpose  :
4785 //=======================================================================
4786 SMESH_MeshEditor::Extrusion_Error
4787 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4788                                        SMESH_Mesh*          theTrack,
4789                                        const SMDS_MeshNode* theN1,
4790                                        const bool           theHasAngles,
4791                                        list<double>&        theAngles,
4792                                        const bool           theLinearVariation,
4793                                        const bool           theHasRefPoint,
4794                                        const gp_Pnt&        theRefPoint,
4795                                        const bool           theMakeGroups)
4796 {
4797   myLastCreatedElems.Clear();
4798   myLastCreatedNodes.Clear();
4799
4800   int aNbE;
4801   std::list<double> aPrms;
4802   TIDSortedElemSet::iterator itElem;
4803
4804   gp_XYZ aGC;
4805   TopoDS_Edge aTrackEdge;
4806   TopoDS_Vertex aV1, aV2;
4807
4808   SMDS_ElemIteratorPtr aItE;
4809   SMDS_NodeIteratorPtr aItN;
4810   SMDSAbs_ElementType aTypeE;
4811
4812   TNodeOfNodeListMap mapNewNodes;
4813
4814   // 1. Check data
4815   aNbE = theElements.size();
4816   // nothing to do
4817   if ( !aNbE )
4818     return EXTR_NO_ELEMENTS;
4819
4820   // 1.1 Track Pattern
4821   ASSERT( theTrack );
4822
4823   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4824
4825   aItE = pMeshDS->elementsIterator();
4826   while ( aItE->more() ) {
4827     const SMDS_MeshElement* pE = aItE->next();
4828     aTypeE = pE->GetType();
4829     // Pattern must contain links only
4830     if ( aTypeE != SMDSAbs_Edge )
4831       return EXTR_PATH_NOT_EDGE;
4832   }
4833
4834   list<SMESH_MeshEditor_PathPoint> fullList;
4835
4836   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4837   // Sub shape for the Pattern must be an Edge or Wire
4838   if( aS.ShapeType() == TopAbs_EDGE ) {
4839     aTrackEdge = TopoDS::Edge( aS );
4840     // the Edge must not be degenerated
4841     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4842       return EXTR_BAD_PATH_SHAPE;
4843     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4844     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4845     const SMDS_MeshNode* aN1 = aItN->next();
4846     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4847     const SMDS_MeshNode* aN2 = aItN->next();
4848     // starting node must be aN1 or aN2
4849     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4850       return EXTR_BAD_STARTING_NODE;
4851     aItN = pMeshDS->nodesIterator();
4852     while ( aItN->more() ) {
4853       const SMDS_MeshNode* pNode = aItN->next();
4854       if( pNode==aN1 || pNode==aN2 ) continue;
4855       const SMDS_EdgePosition* pEPos =
4856         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4857       double aT = pEPos->GetUParameter();
4858       aPrms.push_back( aT );
4859     }
4860     //Extrusion_Error err =
4861     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4862   }
4863   else if( aS.ShapeType() == TopAbs_WIRE ) {
4864     list< SMESH_subMesh* > LSM;
4865     TopTools_SequenceOfShape Edges;
4866     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4867     for(; eExp.More(); eExp.Next()) {
4868       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4869       if( BRep_Tool::Degenerated(E) ) continue;
4870       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4871       if(SM) {
4872         LSM.push_back(SM);
4873         Edges.Append(E);
4874       }
4875     }
4876     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4877     int startNid = theN1->GetID();
4878     TColStd_MapOfInteger UsedNums;
4879     int NbEdges = Edges.Length();
4880     int i = 1;
4881     for(; i<=NbEdges; i++) {
4882       int k = 0;
4883       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4884       for(; itLSM!=LSM.end(); itLSM++) {
4885         k++;
4886         if(UsedNums.Contains(k)) continue;
4887         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4888         SMESH_subMesh* locTrack = *itLSM;
4889         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4890         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4891         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4892         const SMDS_MeshNode* aN1 = aItN->next();
4893         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4894         const SMDS_MeshNode* aN2 = aItN->next();
4895         // starting node must be aN1 or aN2
4896         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4897         // 2. Collect parameters on the track edge
4898         aPrms.clear();
4899         aItN = locMeshDS->GetNodes();
4900         while ( aItN->more() ) {
4901           const SMDS_MeshNode* pNode = aItN->next();
4902           const SMDS_EdgePosition* pEPos =
4903             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4904           double aT = pEPos->GetUParameter();
4905           aPrms.push_back( aT );
4906         }
4907         list<SMESH_MeshEditor_PathPoint> LPP;
4908         //Extrusion_Error err =
4909         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4910         LLPPs.push_back(LPP);
4911         UsedNums.Add(k);
4912         // update startN for search following egde
4913         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4914         else startNid = aN1->GetID();
4915         break;
4916       }
4917     }
4918     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4919     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4920     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4921     for(; itPP!=firstList.end(); itPP++) {
4922       fullList.push_back( *itPP );
4923     }
4924     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4925     fullList.pop_back();
4926     itLLPP++;
4927     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4928       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4929       itPP = currList.begin();
4930       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4931       gp_Dir D1 = PP1.Tangent();
4932       gp_Dir D2 = PP2.Tangent();
4933       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4934                            (D1.Z()+D2.Z())/2 ) );
4935       PP1.SetTangent(Dnew);
4936       fullList.push_back(PP1);
4937       itPP++;
4938       for(; itPP!=currList.end(); itPP++) {
4939         fullList.push_back( *itPP );
4940       }
4941       PP1 = fullList.back();
4942       fullList.pop_back();
4943     }
4944     // if wire not closed
4945     fullList.push_back(PP1);
4946     // else ???
4947   }
4948   else {
4949     return EXTR_BAD_PATH_SHAPE;
4950   }
4951
4952   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4953                           theHasRefPoint, theRefPoint, theMakeGroups);
4954 }
4955
4956
4957 //=======================================================================
4958 //function : MakeEdgePathPoints
4959 //purpose  : auxilary for ExtrusionAlongTrack
4960 //=======================================================================
4961 SMESH_MeshEditor::Extrusion_Error
4962 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4963                                      const TopoDS_Edge& aTrackEdge,
4964                                      bool FirstIsStart,
4965                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4966 {
4967   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4968   aTolVec=1.e-7;
4969   aTolVec2=aTolVec*aTolVec;
4970   double aT1, aT2;
4971   TopoDS_Vertex aV1, aV2;
4972   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4973   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4974   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4975   // 2. Collect parameters on the track edge
4976   aPrms.push_front( aT1 );
4977   aPrms.push_back( aT2 );
4978   // sort parameters
4979   aPrms.sort();
4980   if( FirstIsStart ) {
4981     if ( aT1 > aT2 ) {
4982       aPrms.reverse();
4983     }
4984   }
4985   else {
4986     if ( aT2 > aT1 ) {
4987       aPrms.reverse();
4988     }
4989   }
4990   // 3. Path Points
4991   SMESH_MeshEditor_PathPoint aPP;
4992   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4993   std::list<double>::iterator aItD = aPrms.begin();
4994   for(; aItD != aPrms.end(); ++aItD) {
4995     double aT = *aItD;
4996     gp_Pnt aP3D;
4997     gp_Vec aVec;
4998     aC3D->D1( aT, aP3D, aVec );
4999     aL2 = aVec.SquareMagnitude();
5000     if ( aL2 < aTolVec2 )
5001       return EXTR_CANT_GET_TANGENT;
5002     gp_Dir aTgt( aVec );
5003     aPP.SetPnt( aP3D );
5004     aPP.SetTangent( aTgt );
5005     aPP.SetParameter( aT );
5006     LPP.push_back(aPP);
5007   }
5008   return EXTR_OK;
5009 }
5010
5011
5012 //=======================================================================
5013 //function : MakeExtrElements
5014 //purpose  : auxilary for ExtrusionAlongTrack
5015 //=======================================================================
5016 SMESH_MeshEditor::Extrusion_Error
5017 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5018                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5019                                    const bool theHasAngles,
5020                                    list<double>& theAngles,
5021                                    const bool theLinearVariation,
5022                                    const bool theHasRefPoint,
5023                                    const gp_Pnt& theRefPoint,
5024                                    const bool theMakeGroups)
5025 {
5026   MESSAGE("MakeExtrElements");
5027   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5028   int aNbTP = fullList.size();
5029   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5030   // Angles
5031   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5032     LinearAngleVariation(aNbTP-1, theAngles);
5033   }
5034   vector<double> aAngles( aNbTP );
5035   int j = 0;
5036   for(; j<aNbTP; ++j) {
5037     aAngles[j] = 0.;
5038   }
5039   if ( theHasAngles ) {
5040     double anAngle;;
5041     std::list<double>::iterator aItD = theAngles.begin();
5042     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5043       anAngle = *aItD;
5044       aAngles[j] = anAngle;
5045     }
5046   }
5047   // fill vector of path points with angles
5048   //aPPs.resize(fullList.size());
5049   j = -1;
5050   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5051   for(; itPP!=fullList.end(); itPP++) {
5052     j++;
5053     SMESH_MeshEditor_PathPoint PP = *itPP;
5054     PP.SetAngle(aAngles[j]);
5055     aPPs[j] = PP;
5056   }
5057
5058   TNodeOfNodeListMap mapNewNodes;
5059   TElemOfVecOfNnlmiMap mapElemNewNodes;
5060   TElemOfElemListMap newElemsMap;
5061   TIDSortedElemSet::iterator itElem;
5062   double aX, aY, aZ;
5063   int aNb;
5064   SMDSAbs_ElementType aTypeE;
5065   // source elements for each generated one
5066   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5067
5068   // 3. Center of rotation aV0
5069   gp_Pnt aV0 = theRefPoint;
5070   gp_XYZ aGC;
5071   if ( !theHasRefPoint ) {
5072     aNb = 0;
5073     aGC.SetCoord( 0.,0.,0. );
5074
5075     itElem = theElements.begin();
5076     for ( ; itElem != theElements.end(); itElem++ ) {
5077       const SMDS_MeshElement* elem = *itElem;
5078
5079       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5080       while ( itN->more() ) {
5081         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5082         aX = node->X();
5083         aY = node->Y();
5084         aZ = node->Z();
5085
5086         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5087           list<const SMDS_MeshNode*> aLNx;
5088           mapNewNodes[node] = aLNx;
5089           //
5090           gp_XYZ aXYZ( aX, aY, aZ );
5091           aGC += aXYZ;
5092           ++aNb;
5093         }
5094       }
5095     }
5096     aGC /= aNb;
5097     aV0.SetXYZ( aGC );
5098   } // if (!theHasRefPoint) {
5099   mapNewNodes.clear();
5100
5101   // 4. Processing the elements
5102   SMESHDS_Mesh* aMesh = GetMeshDS();
5103
5104   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5105     // check element type
5106     const SMDS_MeshElement* elem = *itElem;
5107     aTypeE = elem->GetType();
5108     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5109       continue;
5110
5111     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5112     newNodesItVec.reserve( elem->NbNodes() );
5113
5114     // loop on elem nodes
5115     int nodeIndex = -1;
5116     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5117     while ( itN->more() )
5118     {
5119       ++nodeIndex;
5120       // check if a node has been already processed
5121       const SMDS_MeshNode* node =
5122         static_cast<const SMDS_MeshNode*>( itN->next() );
5123       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5124       if ( nIt == mapNewNodes.end() ) {
5125         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5126         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5127
5128         // make new nodes
5129         aX = node->X();  aY = node->Y(); aZ = node->Z();
5130
5131         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5132         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5133         gp_Ax1 anAx1, anAxT1T0;
5134         gp_Dir aDT1x, aDT0x, aDT1T0;
5135
5136         aTolAng=1.e-4;
5137
5138         aV0x = aV0;
5139         aPN0.SetCoord(aX, aY, aZ);
5140
5141         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5142         aP0x = aPP0.Pnt();
5143         aDT0x= aPP0.Tangent();
5144         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5145
5146         for ( j = 1; j < aNbTP; ++j ) {
5147           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5148           aP1x = aPP1.Pnt();
5149           aDT1x = aPP1.Tangent();
5150           aAngle1x = aPP1.Angle();
5151
5152           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5153           // Translation
5154           gp_Vec aV01x( aP0x, aP1x );
5155           aTrsf.SetTranslation( aV01x );
5156
5157           // traslated point
5158           aV1x = aV0x.Transformed( aTrsf );
5159           aPN1 = aPN0.Transformed( aTrsf );
5160
5161           // rotation 1 [ T1,T0 ]
5162           aAngleT1T0=-aDT1x.Angle( aDT0x );
5163           if (fabs(aAngleT1T0) > aTolAng) {
5164             aDT1T0=aDT1x^aDT0x;
5165             anAxT1T0.SetLocation( aV1x );
5166             anAxT1T0.SetDirection( aDT1T0 );
5167             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5168
5169             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5170           }
5171
5172           // rotation 2
5173           if ( theHasAngles ) {
5174             anAx1.SetLocation( aV1x );
5175             anAx1.SetDirection( aDT1x );
5176             aTrsfRot.SetRotation( anAx1, aAngle1x );
5177
5178             aPN1 = aPN1.Transformed( aTrsfRot );
5179           }
5180
5181           // make new node
5182           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5183           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5184             // create additional node
5185             double x = ( aPN1.X() + aPN0.X() )/2.;
5186             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5187             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5188             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5189             myLastCreatedNodes.Append(newNode);
5190             srcNodes.Append( node );
5191             listNewNodes.push_back( newNode );
5192           }
5193           aX = aPN1.X();
5194           aY = aPN1.Y();
5195           aZ = aPN1.Z();
5196           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5197           myLastCreatedNodes.Append(newNode);
5198           srcNodes.Append( node );
5199           listNewNodes.push_back( newNode );
5200
5201           aPN0 = aPN1;
5202           aP0x = aP1x;
5203           aV0x = aV1x;
5204           aDT0x = aDT1x;
5205         }
5206       }
5207
5208       else {
5209         // if current elem is quadratic and current node is not medium
5210         // we have to check - may be it is needed to insert additional nodes
5211         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5212           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5213           if(listNewNodes.size()==aNbTP-1) {
5214             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5215             gp_XYZ P(node->X(), node->Y(), node->Z());
5216             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5217             int i;
5218             for(i=0; i<aNbTP-1; i++) {
5219               const SMDS_MeshNode* N = *it;
5220               double x = ( N->X() + P.X() )/2.;
5221               double y = ( N->Y() + P.Y() )/2.;
5222               double z = ( N->Z() + P.Z() )/2.;
5223               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5224               srcNodes.Append( node );
5225               myLastCreatedNodes.Append(newN);
5226               aNodes[2*i] = newN;
5227               aNodes[2*i+1] = N;
5228               P = gp_XYZ(N->X(),N->Y(),N->Z());
5229             }
5230             listNewNodes.clear();
5231             for(i=0; i<2*(aNbTP-1); i++) {
5232               listNewNodes.push_back(aNodes[i]);
5233             }
5234           }
5235         }
5236       }
5237
5238       newNodesItVec.push_back( nIt );
5239     }
5240     // make new elements
5241     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5242     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5243     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5244   }
5245
5246   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5247
5248   if ( theMakeGroups )
5249     generateGroups( srcNodes, srcElems, "extruded");
5250
5251   return EXTR_OK;
5252 }
5253
5254
5255 //=======================================================================
5256 //function : LinearAngleVariation
5257 //purpose  : auxilary for ExtrusionAlongTrack
5258 //=======================================================================
5259 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5260                                             list<double>& Angles)
5261 {
5262   int nbAngles = Angles.size();
5263   if( nbSteps > nbAngles ) {
5264     vector<double> theAngles(nbAngles);
5265     list<double>::iterator it = Angles.begin();
5266     int i = -1;
5267     for(; it!=Angles.end(); it++) {
5268       i++;
5269       theAngles[i] = (*it);
5270     }
5271     list<double> res;
5272     double rAn2St = double( nbAngles ) / double( nbSteps );
5273     double angPrev = 0, angle;
5274     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5275       double angCur = rAn2St * ( iSt+1 );
5276       double angCurFloor  = floor( angCur );
5277       double angPrevFloor = floor( angPrev );
5278       if ( angPrevFloor == angCurFloor )
5279         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5280       else {
5281         int iP = int( angPrevFloor );
5282         double angPrevCeil = ceil(angPrev);
5283         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5284
5285         int iC = int( angCurFloor );
5286         if ( iC < nbAngles )
5287           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5288
5289         iP = int( angPrevCeil );
5290         while ( iC-- > iP )
5291           angle += theAngles[ iC ];
5292       }
5293       res.push_back(angle);
5294       angPrev = angCur;
5295     }
5296     Angles.clear();
5297     it = res.begin();
5298     for(; it!=res.end(); it++)
5299       Angles.push_back( *it );
5300   }
5301 }
5302
5303
5304 //================================================================================
5305 /*!
5306  * \brief Move or copy theElements applying theTrsf to their nodes
5307  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5308  *  \param theTrsf - transformation to apply
5309  *  \param theCopy - if true, create translated copies of theElems
5310  *  \param theMakeGroups - if true and theCopy, create translated groups
5311  *  \param theTargetMesh - mesh to copy translated elements into
5312  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5313  */
5314 //================================================================================
5315
5316 SMESH_MeshEditor::PGroupIDs
5317 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5318                              const gp_Trsf&     theTrsf,
5319                              const bool         theCopy,
5320                              const bool         theMakeGroups,
5321                              SMESH_Mesh*        theTargetMesh)
5322 {
5323   myLastCreatedElems.Clear();
5324   myLastCreatedNodes.Clear();
5325
5326   bool needReverse = false;
5327   string groupPostfix;
5328   switch ( theTrsf.Form() ) {
5329   case gp_PntMirror:
5330     MESSAGE("gp_PntMirror");
5331     needReverse = true;
5332     groupPostfix = "mirrored";
5333     break;
5334   case gp_Ax1Mirror:
5335     MESSAGE("gp_Ax1Mirror");
5336     groupPostfix = "mirrored";
5337     break;
5338   case gp_Ax2Mirror:
5339     MESSAGE("gp_Ax2Mirror");
5340     needReverse = true;
5341     groupPostfix = "mirrored";
5342     break;
5343   case gp_Rotation:
5344     MESSAGE("gp_Rotation");
5345     groupPostfix = "rotated";
5346     break;
5347   case gp_Translation:
5348     MESSAGE("gp_Translation");
5349     groupPostfix = "translated";
5350     break;
5351   case gp_Scale:
5352     MESSAGE("gp_Scale");
5353     groupPostfix = "scaled";
5354     break;
5355   case gp_CompoundTrsf: // different scale by axis
5356     MESSAGE("gp_CompoundTrsf");
5357     groupPostfix = "scaled";
5358     break;
5359   default:
5360     MESSAGE("default");
5361     needReverse = false;
5362     groupPostfix = "transformed";
5363   }
5364
5365   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5366   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5367   SMESHDS_Mesh* aMesh    = GetMeshDS();
5368
5369
5370   // map old node to new one
5371   TNodeNodeMap nodeMap;
5372
5373   // elements sharing moved nodes; those of them which have all
5374   // nodes mirrored but are not in theElems are to be reversed
5375   TIDSortedElemSet inverseElemSet;
5376
5377   // source elements for each generated one
5378   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5379
5380   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5381   TIDSortedElemSet orphanNode;
5382
5383   if ( theElems.empty() ) // transform the whole mesh
5384   {
5385     // add all elements
5386     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5387     while ( eIt->more() ) theElems.insert( eIt->next() );
5388     // add orphan nodes
5389     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5390     while ( nIt->more() )
5391     {
5392       const SMDS_MeshNode* node = nIt->next();
5393       if ( node->NbInverseElements() == 0)
5394         orphanNode.insert( node );
5395     }
5396   }
5397
5398   // loop on elements to transform nodes : first orphan nodes then elems
5399   TIDSortedElemSet::iterator itElem;
5400   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5401   for (int i=0; i<2; i++)
5402   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5403     const SMDS_MeshElement* elem = *itElem;
5404     if ( !elem )
5405       continue;
5406
5407     // loop on elem nodes
5408     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5409     while ( itN->more() ) {
5410
5411       const SMDS_MeshNode* node = cast2Node( itN->next() );
5412       // check if a node has been already transformed
5413       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5414         nodeMap.insert( make_pair ( node, node ));
5415       if ( !n2n_isnew.second )
5416         continue;
5417
5418       double coord[3];
5419       coord[0] = node->X();
5420       coord[1] = node->Y();
5421       coord[2] = node->Z();
5422       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5423       if ( theTargetMesh ) {
5424         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5425         n2n_isnew.first->second = newNode;
5426         myLastCreatedNodes.Append(newNode);
5427         srcNodes.Append( node );
5428       }
5429       else if ( theCopy ) {
5430         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5431         n2n_isnew.first->second = newNode;
5432         myLastCreatedNodes.Append(newNode);
5433         srcNodes.Append( node );
5434       }
5435       else {
5436         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5437         // node position on shape becomes invalid
5438         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5439           ( SMDS_SpacePosition::originSpacePosition() );
5440       }
5441
5442       // keep inverse elements
5443       if ( !theCopy && !theTargetMesh && needReverse ) {
5444         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5445         while ( invElemIt->more() ) {
5446           const SMDS_MeshElement* iel = invElemIt->next();
5447           inverseElemSet.insert( iel );
5448         }
5449       }
5450     }
5451   }
5452
5453   // either create new elements or reverse mirrored ones
5454   if ( !theCopy && !needReverse && !theTargetMesh )
5455     return PGroupIDs();
5456
5457   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5458   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5459     theElems.insert( *invElemIt );
5460
5461   // replicate or reverse elements
5462   // TODO revoir ordre reverse vtk
5463   enum {
5464     REV_TETRA   = 0,  //  = nbNodes - 4
5465     REV_PYRAMID = 1,  //  = nbNodes - 4
5466     REV_PENTA   = 2,  //  = nbNodes - 4
5467     REV_FACE    = 3,
5468     REV_HEXA    = 4,  //  = nbNodes - 4
5469     FORWARD     = 5
5470   };
5471   int index[][8] = {
5472     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5473     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5474     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5475     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5476     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5477     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5478   };
5479
5480   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5481   {
5482     const SMDS_MeshElement* elem = *itElem;
5483     if ( !elem || elem->GetType() == SMDSAbs_Node )
5484       continue;
5485
5486     int nbNodes = elem->NbNodes();
5487     int elemType = elem->GetType();
5488
5489     if (elem->IsPoly()) {
5490       // Polygon or Polyhedral Volume
5491       switch ( elemType ) {
5492       case SMDSAbs_Face:
5493         {
5494           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5495           int iNode = 0;
5496           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5497           while (itN->more()) {
5498             const SMDS_MeshNode* node =
5499               static_cast<const SMDS_MeshNode*>(itN->next());
5500             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5501             if (nodeMapIt == nodeMap.end())
5502               break; // not all nodes transformed
5503             if (needReverse) {
5504               // reverse mirrored faces and volumes
5505               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5506             } else {
5507               poly_nodes[iNode] = (*nodeMapIt).second;
5508             }
5509             iNode++;
5510           }
5511           if ( iNode != nbNodes )
5512             continue; // not all nodes transformed
5513
5514           if ( theTargetMesh ) {
5515             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5516             srcElems.Append( elem );
5517           }
5518           else if ( theCopy ) {
5519             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5520             srcElems.Append( elem );
5521           }
5522           else {
5523             aMesh->ChangePolygonNodes(elem, poly_nodes);
5524           }
5525         }
5526         break;
5527       case SMDSAbs_Volume:
5528         {
5529           // ATTENTION: Reversing is not yet done!!!
5530           const SMDS_VtkVolume* aPolyedre =
5531             dynamic_cast<const SMDS_VtkVolume*>( elem );
5532           if (!aPolyedre) {
5533             MESSAGE("Warning: bad volumic element");
5534             continue;
5535           }
5536
5537           vector<const SMDS_MeshNode*> poly_nodes;
5538           vector<int> quantities;
5539
5540           bool allTransformed = true;
5541           int nbFaces = aPolyedre->NbFaces();
5542           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5543             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5544             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5545               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5546               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5547               if (nodeMapIt == nodeMap.end()) {
5548                 allTransformed = false; // not all nodes transformed
5549               } else {
5550                 poly_nodes.push_back((*nodeMapIt).second);
5551               }
5552             }
5553             quantities.push_back(nbFaceNodes);
5554           }
5555           if ( !allTransformed )
5556             continue; // not all nodes transformed
5557
5558           if ( theTargetMesh ) {
5559             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5560             srcElems.Append( elem );
5561           }
5562           else if ( theCopy ) {
5563             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5564             srcElems.Append( elem );
5565           }
5566           else {
5567             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5568           }
5569         }
5570         break;
5571       default:;
5572       }
5573       continue;
5574     }
5575
5576     // Regular elements
5577     int* i = index[ FORWARD ];
5578     if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5579       if ( elemType == SMDSAbs_Face )
5580         i = index[ REV_FACE ];
5581       else
5582         i = index[ nbNodes - 4 ];
5583     }
5584     if(elem->IsQuadratic()) {
5585       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5586       i = anIds;
5587       if(needReverse) {
5588         if(nbNodes==3) { // quadratic edge
5589           static int anIds[] = {1,0,2};
5590           i = anIds;
5591         }
5592         else if(nbNodes==6) { // quadratic triangle
5593           static int anIds[] = {0,2,1,5,4,3};
5594           i = anIds;
5595         }
5596         else if(nbNodes==8) { // quadratic quadrangle
5597           static int anIds[] = {0,3,2,1,7,6,5,4};
5598           i = anIds;
5599         }
5600         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5601           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5602           i = anIds;
5603         }
5604         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5605           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5606           i = anIds;
5607         }
5608         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5609           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5610           i = anIds;
5611         }
5612         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5613           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5614           i = anIds;
5615         }
5616       }
5617     }
5618
5619     // find transformed nodes
5620     vector<const SMDS_MeshNode*> nodes(nbNodes);
5621     int iNode = 0;
5622     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5623     while ( itN->more() ) {
5624       const SMDS_MeshNode* node =
5625         static_cast<const SMDS_MeshNode*>( itN->next() );
5626       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5627       if ( nodeMapIt == nodeMap.end() )
5628         break; // not all nodes transformed
5629       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5630     }
5631     if ( iNode != nbNodes )
5632       continue; // not all nodes transformed
5633
5634     if ( theTargetMesh ) {
5635       if ( SMDS_MeshElement* copy =
5636            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5637         myLastCreatedElems.Append( copy );
5638         srcElems.Append( elem );
5639       }
5640     }
5641     else if ( theCopy ) {
5642       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5643         srcElems.Append( elem );
5644     }
5645     else {
5646       // reverse element as it was reversed by transformation
5647       if ( nbNodes > 2 )
5648         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5649     }
5650   }
5651
5652   PGroupIDs newGroupIDs;
5653
5654   if ( ( theMakeGroups && theCopy ) ||
5655        ( theMakeGroups && theTargetMesh ) )
5656     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5657
5658   return newGroupIDs;
5659 }
5660
5661
5662 ////=======================================================================
5663 ////function : Scale
5664 ////purpose  :
5665 ////=======================================================================
5666 //
5667 //SMESH_MeshEditor::PGroupIDs
5668 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5669 //                         const gp_Pnt&            thePoint,
5670 //                         const std::list<double>& theScaleFact,
5671 //                         const bool         theCopy,
5672 //                         const bool         theMakeGroups,
5673 //                         SMESH_Mesh*        theTargetMesh)
5674 //{
5675 //  MESSAGE("Scale");
5676 //  myLastCreatedElems.Clear();
5677 //  myLastCreatedNodes.Clear();
5678 //
5679 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5680 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5681 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
5682 //
5683 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5684 //  std::list<double>::const_iterator itS = theScaleFact.begin();
5685 //  scaleX = (*itS);
5686 //  if(theScaleFact.size()==1) {
5687 //    scaleY = (*itS);
5688 //    scaleZ= (*itS);
5689 //  }
5690 //  if(theScaleFact.size()==2) {
5691 //    itS++;
5692 //    scaleY = (*itS);
5693 //    scaleZ= (*itS);
5694 //  }
5695 //  if(theScaleFact.size()>2) {
5696 //    itS++;
5697 //    scaleY = (*itS);
5698 //    itS++;
5699 //    scaleZ= (*itS);
5700 //  }
5701 //
5702 //  // map old node to new one
5703 //  TNodeNodeMap nodeMap;
5704 //
5705 //  // elements sharing moved nodes; those of them which have all
5706 //  // nodes mirrored but are not in theElems are to be reversed
5707 //  TIDSortedElemSet inverseElemSet;
5708 //
5709 //  // source elements for each generated one
5710 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
5711 //
5712 //  // loop on theElems
5713 //  TIDSortedElemSet::iterator itElem;
5714 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5715 //    const SMDS_MeshElement* elem = *itElem;
5716 //    if ( !elem )
5717 //      continue;
5718 //
5719 //    // loop on elem nodes
5720 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5721 //    while ( itN->more() ) {
5722 //
5723 //      // check if a node has been already transformed
5724 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
5725 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5726 //        nodeMap.insert( make_pair ( node, node ));
5727 //      if ( !n2n_isnew.second )
5728 //        continue;
5729 //
5730 //      //double coord[3];
5731 //      //coord[0] = node->X();
5732 //      //coord[1] = node->Y();
5733 //      //coord[2] = node->Z();
5734 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5735 //      double dx = (node->X() - thePoint.X()) * scaleX;
5736 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
5737 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
5738 //      if ( theTargetMesh ) {
5739 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5740 //        const SMDS_MeshNode * newNode =
5741 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5742 //        n2n_isnew.first->second = newNode;
5743 //        myLastCreatedNodes.Append(newNode);
5744 //        srcNodes.Append( node );
5745 //      }
5746 //      else if ( theCopy ) {
5747 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5748 //        const SMDS_MeshNode * newNode =
5749 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5750 //        n2n_isnew.first->second = newNode;
5751 //        myLastCreatedNodes.Append(newNode);
5752 //        srcNodes.Append( node );
5753 //      }
5754 //      else {
5755 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5756 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5757 //        // node position on shape becomes invalid
5758 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
5759 //          ( SMDS_SpacePosition::originSpacePosition() );
5760 //      }
5761 //
5762 //      // keep inverse elements
5763 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
5764 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5765 //      //  while ( invElemIt->more() ) {
5766 //      //    const SMDS_MeshElement* iel = invElemIt->next();
5767 //      //    inverseElemSet.insert( iel );
5768 //      //  }
5769 //      //}
5770 //    }
5771 //  }
5772 //
5773 //  // either create new elements or reverse mirrored ones
5774 //  //if ( !theCopy && !needReverse && !theTargetMesh )
5775 //  if ( !theCopy && !theTargetMesh )
5776 //    return PGroupIDs();
5777 //
5778 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5779 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5780 //    theElems.insert( *invElemIt );
5781 //
5782 //  // replicate or reverse elements
5783 //
5784 //  enum {
5785 //    REV_TETRA   = 0,  //  = nbNodes - 4
5786 //    REV_PYRAMID = 1,  //  = nbNodes - 4
5787 //    REV_PENTA   = 2,  //  = nbNodes - 4
5788 //    REV_FACE    = 3,
5789 //    REV_HEXA    = 4,  //  = nbNodes - 4
5790 //    FORWARD     = 5
5791 //  };
5792 //  int index[][8] = {
5793 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5794 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5795 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5796 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5797 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5798 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5799 //  };
5800 //
5801 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5802 //  {
5803 //    const SMDS_MeshElement* elem = *itElem;
5804 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
5805 //      continue;
5806 //
5807 //    int nbNodes = elem->NbNodes();
5808 //    int elemType = elem->GetType();
5809 //
5810 //    if (elem->IsPoly()) {
5811 //      // Polygon or Polyhedral Volume
5812 //      switch ( elemType ) {
5813 //      case SMDSAbs_Face:
5814 //        {
5815 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5816 //          int iNode = 0;
5817 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5818 //          while (itN->more()) {
5819 //            const SMDS_MeshNode* node =
5820 //              static_cast<const SMDS_MeshNode*>(itN->next());
5821 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5822 //            if (nodeMapIt == nodeMap.end())
5823 //              break; // not all nodes transformed
5824 //            //if (needReverse) {
5825 //            //  // reverse mirrored faces and volumes
5826 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5827 //            //} else {
5828 //            poly_nodes[iNode] = (*nodeMapIt).second;
5829 //            //}
5830 //            iNode++;
5831 //          }
5832 //          if ( iNode != nbNodes )
5833 //            continue; // not all nodes transformed
5834 //
5835 //          if ( theTargetMesh ) {
5836 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5837 //            srcElems.Append( elem );
5838 //          }
5839 //          else if ( theCopy ) {
5840 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5841 //            srcElems.Append( elem );
5842 //          }
5843 //          else {
5844 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
5845 //          }
5846 //        }
5847 //        break;
5848 //      case SMDSAbs_Volume:
5849 //        {
5850 //          // ATTENTION: Reversing is not yet done!!!
5851 //          const SMDS_VtkVolume* aPolyedre =
5852 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
5853 //          if (!aPolyedre) {
5854 //            MESSAGE("Warning: bad volumic element");
5855 //            continue;
5856 //          }
5857 //
5858 //          vector<const SMDS_MeshNode*> poly_nodes;
5859 //          vector<int> quantities;
5860 //
5861 //          bool allTransformed = true;
5862 //          int nbFaces = aPolyedre->NbFaces();
5863 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5864 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5865 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5866 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5867 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5868 //              if (nodeMapIt == nodeMap.end()) {
5869 //                allTransformed = false; // not all nodes transformed
5870 //              } else {
5871 //                poly_nodes.push_back((*nodeMapIt).second);
5872 //              }
5873 //            }
5874 //            quantities.push_back(nbFaceNodes);
5875 //          }
5876 //          if ( !allTransformed )
5877 //            continue; // not all nodes transformed
5878 //
5879 //          if ( theTargetMesh ) {
5880 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5881 //            srcElems.Append( elem );
5882 //          }
5883 //          else if ( theCopy ) {
5884 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5885 //            srcElems.Append( elem );
5886 //          }
5887 //          else {
5888 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5889 //          }
5890 //        }
5891 //        break;
5892 //      default:;
5893 //      }
5894 //      continue;
5895 //    }
5896 //
5897 //    // Regular elements
5898 //    int* i = index[ FORWARD ];
5899 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5900 //    //  if ( elemType == SMDSAbs_Face )
5901 //    //    i = index[ REV_FACE ];
5902 //    //  else
5903 //    //    i = index[ nbNodes - 4 ];
5904 //
5905 //    if(elem->IsQuadratic()) {
5906 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5907 //      i = anIds;
5908 //      //if(needReverse) {
5909 //      //  if(nbNodes==3) { // quadratic edge
5910 //      //    static int anIds[] = {1,0,2};
5911 //      //    i = anIds;
5912 //      //  }
5913 //      //  else if(nbNodes==6) { // quadratic triangle
5914 //      //    static int anIds[] = {0,2,1,5,4,3};
5915 //      //    i = anIds;
5916 //      //  }
5917 //      //  else if(nbNodes==8) { // quadratic quadrangle
5918 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
5919 //      //    i = anIds;
5920 //      //  }
5921 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5922 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5923 //      //    i = anIds;
5924 //      //  }
5925 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5926 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5927 //      //    i = anIds;
5928 //      //  }
5929 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5930 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5931 //      //    i = anIds;
5932 //      //  }
5933 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5934 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5935 //      //    i = anIds;
5936 //      //  }
5937 //      //}
5938 //    }
5939 //
5940 //    // find transformed nodes
5941 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
5942 //    int iNode = 0;
5943 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5944 //    while ( itN->more() ) {
5945 //      const SMDS_MeshNode* node =
5946 //        static_cast<const SMDS_MeshNode*>( itN->next() );
5947 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5948 //      if ( nodeMapIt == nodeMap.end() )
5949 //        break; // not all nodes transformed
5950 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5951 //    }
5952 //    if ( iNode != nbNodes )
5953 //      continue; // not all nodes transformed
5954 //
5955 //    if ( theTargetMesh ) {
5956 //      if ( SMDS_MeshElement* copy =
5957 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5958 //        myLastCreatedElems.Append( copy );
5959 //        srcElems.Append( elem );
5960 //      }
5961 //    }
5962 //    else if ( theCopy ) {
5963 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5964 //        myLastCreatedElems.Append( copy );
5965 //        srcElems.Append( elem );
5966 //      }
5967 //    }
5968 //    else {
5969 //      // reverse element as it was reversed by transformation
5970 //      if ( nbNodes > 2 )
5971 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5972 //    }
5973 //  }
5974 //
5975 //  PGroupIDs newGroupIDs;
5976 //
5977 //  if ( theMakeGroups && theCopy ||
5978 //       theMakeGroups && theTargetMesh ) {
5979 //    string groupPostfix = "scaled";
5980 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5981 //  }
5982 //
5983 //  return newGroupIDs;
5984 //}
5985
5986
5987 //=======================================================================
5988 /*!
5989  * \brief Create groups of elements made during transformation
5990  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5991  * \param elemGens - elements making corresponding myLastCreatedElems
5992  * \param postfix - to append to names of new groups
5993  */
5994 //=======================================================================
5995
5996 SMESH_MeshEditor::PGroupIDs
5997 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5998                                  const SMESH_SequenceOfElemPtr& elemGens,
5999                                  const std::string&             postfix,
6000                                  SMESH_Mesh*                    targetMesh)
6001 {
6002   PGroupIDs newGroupIDs( new list<int> );
6003   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6004
6005   // Sort existing groups by types and collect their names
6006
6007   // to store an old group and a generated new one
6008   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6009   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6010   // group names
6011   set< string > groupNames;
6012   //
6013   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6014   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6015   while ( groupIt->more() ) {
6016     SMESH_Group * group = groupIt->next();
6017     if ( !group ) continue;
6018     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6019     if ( !groupDS || groupDS->IsEmpty() ) continue;
6020     groupNames.insert( group->GetName() );
6021     groupDS->SetStoreName( group->GetName() );
6022     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6023   }
6024
6025   // Groups creation
6026
6027   // loop on nodes and elements
6028   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6029   {
6030     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6031     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6032     if ( gens.Length() != elems.Length() )
6033       throw SALOME_Exception(LOCALIZED("invalid args"));
6034
6035     // loop on created elements
6036     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6037     {
6038       const SMDS_MeshElement* sourceElem = gens( iElem );
6039       if ( !sourceElem ) {
6040         MESSAGE("generateGroups(): NULL source element");
6041         continue;
6042       }
6043       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6044       if ( groupsOldNew.empty() ) {
6045         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6046           ++iElem; // skip all elements made by sourceElem
6047         continue;
6048       }
6049       // collect all elements made by sourceElem
6050       list< const SMDS_MeshElement* > resultElems;
6051       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6052         if ( resElem != sourceElem )
6053           resultElems.push_back( resElem );
6054       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6055         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6056           if ( resElem != sourceElem )
6057             resultElems.push_back( resElem );
6058       // do not generate element groups from node ones
6059       if ( sourceElem->GetType() == SMDSAbs_Node &&
6060            elems( iElem )->GetType() != SMDSAbs_Node )
6061         continue;
6062
6063       // add resultElems to groups made by ones the sourceElem belongs to
6064       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6065       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6066       {
6067         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6068         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6069         {
6070           SMDS_MeshGroup* & newGroup = gOldNew->second;
6071           if ( !newGroup )// create a new group
6072           {
6073             // make a name
6074             string name = oldGroup->GetStoreName();
6075             if ( !targetMesh ) {
6076               name += "_";
6077               name += postfix;
6078               int nb = 0;
6079               while ( !groupNames.insert( name ).second ) // name exists
6080               {
6081                 if ( nb == 0 ) {
6082                   name += "_1";
6083                 }
6084                 else {
6085                   TCollection_AsciiString nbStr(nb+1);
6086                   name.resize( name.rfind('_')+1 );
6087                   name += nbStr.ToCString();
6088                 }
6089                 ++nb;
6090               }
6091             }
6092             // make a group
6093             int id;
6094             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6095                                                  name.c_str(), id );
6096             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6097             newGroup = & groupDS->SMDSGroup();
6098             newGroupIDs->push_back( id );
6099           }
6100
6101           // fill in a new group
6102           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6103           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6104             newGroup->Add( *resElemIt );
6105         }
6106       }
6107     } // loop on created elements
6108   }// loop on nodes and elements
6109
6110   return newGroupIDs;
6111 }
6112
6113 //================================================================================
6114 /*!
6115  * \brief Return list of group of nodes close to each other within theTolerance
6116  *        Search among theNodes or in the whole mesh if theNodes is empty using
6117  *        an Octree algorithm
6118  */
6119 //================================================================================
6120
6121 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6122                                             const double         theTolerance,
6123                                             TListOfListOfNodes & theGroupsOfNodes)
6124 {
6125   myLastCreatedElems.Clear();
6126   myLastCreatedNodes.Clear();
6127
6128   if ( theNodes.empty() )
6129   { // get all nodes in the mesh
6130     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6131     while ( nIt->more() )
6132       theNodes.insert( theNodes.end(),nIt->next());
6133   }
6134
6135   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6136 }
6137
6138
6139 //=======================================================================
6140 /*!
6141  * \brief Implementation of search for the node closest to point
6142  */
6143 //=======================================================================
6144
6145 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6146 {
6147   //---------------------------------------------------------------------
6148   /*!
6149    * \brief Constructor
6150    */
6151   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6152   {
6153     myMesh = ( SMESHDS_Mesh* ) theMesh;
6154
6155     TIDSortedNodeSet nodes;
6156     if ( theMesh ) {
6157       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6158       while ( nIt->more() )
6159         nodes.insert( nodes.end(), nIt->next() );
6160     }
6161     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6162
6163     // get max size of a leaf box
6164     SMESH_OctreeNode* tree = myOctreeNode;
6165     while ( !tree->isLeaf() )
6166     {
6167       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6168       if ( cIt->more() )
6169         tree = cIt->next();
6170     }
6171     myHalfLeafSize = tree->maxSize() / 2.;
6172   }
6173
6174   //---------------------------------------------------------------------
6175   /*!
6176    * \brief Move node and update myOctreeNode accordingly
6177    */
6178   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6179   {
6180     myOctreeNode->UpdateByMoveNode( node, toPnt );
6181     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6182   }
6183
6184   //---------------------------------------------------------------------
6185   /*!
6186    * \brief Do it's job
6187    */
6188   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6189   {
6190     map<double, const SMDS_MeshNode*> dist2Nodes;
6191     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6192     if ( !dist2Nodes.empty() )
6193       return dist2Nodes.begin()->second;
6194     list<const SMDS_MeshNode*> nodes;
6195     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6196
6197     double minSqDist = DBL_MAX;
6198     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6199     {
6200       // sort leafs by their distance from thePnt
6201       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6202       TDistTreeMap treeMap;
6203       list< SMESH_OctreeNode* > treeList;
6204       list< SMESH_OctreeNode* >::iterator trIt;
6205       treeList.push_back( myOctreeNode );
6206
6207       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6208       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6209       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6210       {
6211         SMESH_OctreeNode* tree = *trIt;
6212         if ( !tree->isLeaf() ) // put children to the queue
6213         {
6214           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6215           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6216           while ( cIt->more() )
6217             treeList.push_back( cIt->next() );
6218         }
6219         else if ( tree->NbNodes() ) // put a tree to the treeMap
6220         {
6221           const Bnd_B3d& box = tree->getBox();
6222           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6223           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6224           if ( !it_in.second ) // not unique distance to box center
6225             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6226         }
6227       }
6228       // find distance after which there is no sense to check tree's
6229       double sqLimit = DBL_MAX;
6230       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6231       if ( treeMap.size() > 5 ) {
6232         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6233         const Bnd_B3d& box = closestTree->getBox();
6234         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6235         sqLimit = limit * limit;
6236       }
6237       // get all nodes from trees
6238       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6239         if ( sqDist_tree->first > sqLimit )
6240           break;
6241         SMESH_OctreeNode* tree = sqDist_tree->second;
6242         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6243       }
6244     }
6245     // find closest among nodes
6246     minSqDist = DBL_MAX;
6247     const SMDS_MeshNode* closestNode = 0;
6248     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6249     for ( ; nIt != nodes.end(); ++nIt ) {
6250       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6251       if ( minSqDist > sqDist ) {
6252         closestNode = *nIt;
6253         minSqDist = sqDist;
6254       }
6255     }
6256     return closestNode;
6257   }
6258
6259   //---------------------------------------------------------------------
6260   /*!
6261    * \brief Destructor
6262    */
6263   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6264
6265   //---------------------------------------------------------------------
6266   /*!
6267    * \brief Return the node tree
6268    */
6269   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6270
6271 private:
6272   SMESH_OctreeNode* myOctreeNode;
6273   SMESHDS_Mesh*     myMesh;
6274   double            myHalfLeafSize; // max size of a leaf box
6275 };
6276
6277 //=======================================================================
6278 /*!
6279  * \brief Return SMESH_NodeSearcher
6280  */
6281 //=======================================================================
6282
6283 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6284 {
6285   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6286 }
6287
6288 // ========================================================================
6289 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6290 {
6291   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6292   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6293   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6294
6295   //=======================================================================
6296   /*!
6297    * \brief Octal tree of bounding boxes of elements
6298    */
6299   //=======================================================================
6300
6301   class ElementBndBoxTree : public SMESH_Octree
6302   {
6303   public:
6304
6305     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6306     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6307     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6308     ~ElementBndBoxTree();
6309
6310   protected:
6311     ElementBndBoxTree() {}
6312     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6313     void buildChildrenData();
6314     Bnd_B3d* buildRootBox();
6315   private:
6316     //!< Bounding box of element
6317     struct ElementBox : public Bnd_B3d
6318     {
6319       const SMDS_MeshElement* _element;
6320       int                     _refCount; // an ElementBox can be included in several tree branches
6321       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6322     };
6323     vector< ElementBox* > _elements;
6324   };
6325
6326   //================================================================================
6327   /*!
6328    * \brief ElementBndBoxTree creation
6329    */
6330   //================================================================================
6331
6332   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6333     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6334   {
6335     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6336     _elements.reserve( nbElems );
6337
6338     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6339     while ( elemIt->more() )
6340       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6341
6342     if ( _elements.size() > MaxNbElemsInLeaf )
6343       compute();
6344     else
6345       myIsLeaf = true;
6346   }
6347
6348   //================================================================================
6349   /*!
6350    * \brief Destructor
6351    */
6352   //================================================================================
6353
6354   ElementBndBoxTree::~ElementBndBoxTree()
6355   {
6356     for ( int i = 0; i < _elements.size(); ++i )
6357       if ( --_elements[i]->_refCount <= 0 )
6358         delete _elements[i];
6359   }
6360
6361   //================================================================================
6362   /*!
6363    * \brief Return the maximal box
6364    */
6365   //================================================================================
6366
6367   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6368   {
6369     Bnd_B3d* box = new Bnd_B3d;
6370     for ( int i = 0; i < _elements.size(); ++i )
6371       box->Add( *_elements[i] );
6372     return box;
6373   }
6374
6375   //================================================================================
6376   /*!
6377    * \brief Redistrubute element boxes among children
6378    */
6379   //================================================================================
6380
6381   void ElementBndBoxTree::buildChildrenData()
6382   {
6383     for ( int i = 0; i < _elements.size(); ++i )
6384     {
6385       for (int j = 0; j < 8; j++)
6386       {
6387         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6388         {
6389           _elements[i]->_refCount++;
6390           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6391         }
6392       }
6393       _elements[i]->_refCount--;
6394     }
6395     _elements.clear();
6396
6397     for (int j = 0; j < 8; j++)
6398     {
6399       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6400       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6401         child->myIsLeaf = true;
6402
6403       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6404         child->_elements.resize( child->_elements.size() ); // compact
6405     }
6406   }
6407
6408   //================================================================================
6409   /*!
6410    * \brief Return elements which can include the point
6411    */
6412   //================================================================================
6413
6414   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6415                                                 TIDSortedElemSet& foundElems)
6416   {
6417     if ( level() && getBox().IsOut( point.XYZ() ))
6418       return;
6419
6420     if ( isLeaf() )
6421     {
6422       for ( int i = 0; i < _elements.size(); ++i )
6423         if ( !_elements[i]->IsOut( point.XYZ() ))
6424           foundElems.insert( _elements[i]->_element );
6425     }
6426     else
6427     {
6428       for (int i = 0; i < 8; i++)
6429         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6430     }
6431   }
6432
6433   //================================================================================
6434   /*!
6435    * \brief Return elements which can be intersected by the line
6436    */
6437   //================================================================================
6438
6439   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6440                                                TIDSortedElemSet& foundElems)
6441   {
6442     if ( level() && getBox().IsOut( line ))
6443       return;
6444
6445     if ( isLeaf() )
6446     {
6447       for ( int i = 0; i < _elements.size(); ++i )
6448         if ( !_elements[i]->IsOut( line ))
6449           foundElems.insert( _elements[i]->_element );
6450     }
6451     else
6452     {
6453       for (int i = 0; i < 8; i++)
6454         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6455     }
6456   }
6457
6458   //================================================================================
6459   /*!
6460    * \brief Construct the element box
6461    */
6462   //================================================================================
6463
6464   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6465   {
6466     _element  = elem;
6467     _refCount = 1;
6468     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6469     while ( nIt->more() )
6470       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6471     Enlarge( tolerance );
6472   }
6473
6474 } // namespace
6475
6476 //=======================================================================
6477 /*!
6478  * \brief Implementation of search for the elements by point and
6479  *        of classification of point in 2D mesh
6480  */
6481 //=======================================================================
6482
6483 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6484 {
6485   SMESHDS_Mesh*                _mesh;
6486   SMDS_ElemIteratorPtr         _meshPartIt;
6487   ElementBndBoxTree*           _ebbTree;
6488   SMESH_NodeSearcherImpl*      _nodeSearcher;
6489   SMDSAbs_ElementType          _elementType;
6490   double                       _tolerance;
6491   bool                         _outerFacesFound;
6492   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6493
6494   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6495     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6496   ~SMESH_ElementSearcherImpl()
6497   {
6498     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6499     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6500   }
6501   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6502                                   SMDSAbs_ElementType                type,
6503                                   vector< const SMDS_MeshElement* >& foundElements);
6504   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6505
6506   void GetElementsNearLine( const gp_Ax1&                      line,
6507                             SMDSAbs_ElementType                type,
6508                             vector< const SMDS_MeshElement* >& foundElems);
6509   double getTolerance();
6510   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6511                             const double tolerance, double & param);
6512   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6513   bool isOuterBoundary(const SMDS_MeshElement* face) const
6514   {
6515     return _outerFaces.empty() || _outerFaces.count(face);
6516   }
6517   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6518   {
6519     const SMDS_MeshElement* _face;
6520     gp_Vec                  _faceNorm;
6521     bool                    _coincides; //!< the line lays in face plane
6522     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6523       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6524   };
6525   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6526   {
6527     SMESH_TLink      _link;
6528     TIDSortedElemSet _faces;
6529     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6530       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6531   };
6532 };
6533
6534 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6535 {
6536   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6537              << ", _coincides="<<i._coincides << ")";
6538 }
6539
6540 //=======================================================================
6541 /*!
6542  * \brief define tolerance for search
6543  */
6544 //=======================================================================
6545
6546 double SMESH_ElementSearcherImpl::getTolerance()
6547 {
6548   if ( _tolerance < 0 )
6549   {
6550     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6551
6552     _tolerance = 0;
6553     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6554     {
6555       double boxSize = _nodeSearcher->getTree()->maxSize();
6556       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6557     }
6558     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6559     {
6560       double boxSize = _ebbTree->maxSize();
6561       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6562     }
6563     if ( _tolerance == 0 )
6564     {
6565       // define tolerance by size of a most complex element
6566       int complexType = SMDSAbs_Volume;
6567       while ( complexType > SMDSAbs_All &&
6568               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6569         --complexType;
6570       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6571       double elemSize;
6572       if ( complexType == int( SMDSAbs_Node ))
6573       {
6574         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6575         elemSize = 1;
6576         if ( meshInfo.NbNodes() > 2 )
6577           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6578       }
6579       else
6580       {
6581         SMDS_ElemIteratorPtr elemIt =
6582             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6583         const SMDS_MeshElement* elem = elemIt->next();
6584         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6585         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6586         elemSize = 0;
6587         while ( nodeIt->more() )
6588         {
6589           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6590           elemSize = max( dist, elemSize );
6591         }
6592       }
6593       _tolerance = 1e-4 * elemSize;
6594     }
6595   }
6596   return _tolerance;
6597 }
6598
6599 //================================================================================
6600 /*!
6601  * \brief Find intersection of the line and an edge of face and return parameter on line
6602  */
6603 //================================================================================
6604
6605 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6606                                                      const SMDS_MeshElement* face,
6607                                                      const double            tol,
6608                                                      double &                param)
6609 {
6610   int nbInts = 0;
6611   param = 0;
6612
6613   GeomAPI_ExtremaCurveCurve anExtCC;
6614   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6615   
6616   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6617   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6618   {
6619     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6620                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6621     anExtCC.Init( lineCurve, edge);
6622     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6623     {
6624       Quantity_Parameter pl, pe;
6625       anExtCC.LowerDistanceParameters( pl, pe );
6626       param += pl;
6627       if ( ++nbInts == 2 )
6628         break;
6629     }
6630   }
6631   if ( nbInts > 0 ) param /= nbInts;
6632   return nbInts > 0;
6633 }
6634 //================================================================================
6635 /*!
6636  * \brief Find all faces belonging to the outer boundary of mesh
6637  */
6638 //================================================================================
6639
6640 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6641 {
6642   if ( _outerFacesFound ) return;
6643
6644   // Collect all outer faces by passing from one outer face to another via their links
6645   // and BTW find out if there are internal faces at all.
6646
6647   // checked links and links where outer boundary meets internal one
6648   set< SMESH_TLink > visitedLinks, seamLinks;
6649
6650   // links to treat with already visited faces sharing them
6651   list < TFaceLink > startLinks;
6652
6653   // load startLinks with the first outerFace
6654   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6655   _outerFaces.insert( outerFace );
6656
6657   TIDSortedElemSet emptySet;
6658   while ( !startLinks.empty() )
6659   {
6660     const SMESH_TLink& link  = startLinks.front()._link;
6661     TIDSortedElemSet&  faces = startLinks.front()._faces;
6662
6663     outerFace = *faces.begin();
6664     // find other faces sharing the link
6665     const SMDS_MeshElement* f;
6666     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6667       faces.insert( f );
6668
6669     // select another outer face among the found 
6670     const SMDS_MeshElement* outerFace2 = 0;
6671     if ( faces.size() == 2 )
6672     {
6673       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6674     }
6675     else if ( faces.size() > 2 )
6676     {
6677       seamLinks.insert( link );
6678
6679       // link direction within the outerFace
6680       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6681                    SMESH_TNodeXYZ( link.node2()));
6682       int i1 = outerFace->GetNodeIndex( link.node1() );
6683       int i2 = outerFace->GetNodeIndex( link.node2() );
6684       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6685       if ( rev ) n1n2.Reverse();
6686       // outerFace normal
6687       gp_XYZ ofNorm, fNorm;
6688       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6689       {
6690         // direction from the link inside outerFace
6691         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6692         // sort all other faces by angle with the dirInOF
6693         map< double, const SMDS_MeshElement* > angle2Face;
6694         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6695         for ( ; face != faces.end(); ++face )
6696         {
6697           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6698             continue;
6699           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6700           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6701           if ( angle < 0 ) angle += 2*PI;
6702           angle2Face.insert( make_pair( angle, *face ));
6703         }
6704         if ( !angle2Face.empty() )
6705           outerFace2 = angle2Face.begin()->second;
6706       }
6707     }
6708     // store the found outer face and add its links to continue seaching from
6709     if ( outerFace2 )
6710     {
6711       _outerFaces.insert( outerFace );
6712       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6713       for ( int i = 0; i < nbNodes; ++i )
6714       {
6715         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6716         if ( visitedLinks.insert( link2 ).second )
6717           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6718       }
6719     }
6720     startLinks.pop_front();
6721   }
6722   _outerFacesFound = true;
6723
6724   if ( !seamLinks.empty() )
6725   {
6726     // There are internal boundaries touching the outher one,
6727     // find all faces of internal boundaries in order to find
6728     // faces of boundaries of holes, if any.
6729     
6730   }
6731   else
6732   {
6733     _outerFaces.clear();
6734   }
6735 }
6736
6737 //=======================================================================
6738 /*!
6739  * \brief Find elements of given type where the given point is IN or ON.
6740  *        Returns nb of found elements and elements them-selves.
6741  *
6742  * 'ALL' type means elements of any type excluding nodes and 0D elements
6743  */
6744 //=======================================================================
6745
6746 int SMESH_ElementSearcherImpl::
6747 FindElementsByPoint(const gp_Pnt&                      point,
6748                     SMDSAbs_ElementType                type,
6749                     vector< const SMDS_MeshElement* >& foundElements)
6750 {
6751   foundElements.clear();
6752
6753   double tolerance = getTolerance();
6754
6755   // =================================================================================
6756   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6757   {
6758     if ( !_nodeSearcher )
6759       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6760
6761     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6762     if ( !closeNode ) return foundElements.size();
6763
6764     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6765       return foundElements.size(); // to far from any node
6766
6767     if ( type == SMDSAbs_Node )
6768     {
6769       foundElements.push_back( closeNode );
6770     }
6771     else
6772     {
6773       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6774       while ( elemIt->more() )
6775         foundElements.push_back( elemIt->next() );
6776     }
6777   }
6778   // =================================================================================
6779   else // elements more complex than 0D
6780   {
6781     if ( !_ebbTree || _elementType != type )
6782     {
6783       if ( _ebbTree ) delete _ebbTree;
6784       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6785     }
6786     TIDSortedElemSet suspectElems;
6787     _ebbTree->getElementsNearPoint( point, suspectElems );
6788     TIDSortedElemSet::iterator elem = suspectElems.begin();
6789     for ( ; elem != suspectElems.end(); ++elem )
6790       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6791         foundElements.push_back( *elem );
6792   }
6793   return foundElements.size();
6794 }
6795
6796 //================================================================================
6797 /*!
6798  * \brief Classify the given point in the closed 2D mesh
6799  */
6800 //================================================================================
6801
6802 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6803 {
6804   double tolerance = getTolerance();
6805   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6806   {
6807     if ( _ebbTree ) delete _ebbTree;
6808     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6809   }
6810   // Algo: analyse transition of a line starting at the point through mesh boundary;
6811   // try three lines parallel to axis of the coordinate system and perform rough
6812   // analysis. If solution is not clear perform thorough analysis.
6813
6814   const int nbAxes = 3;
6815   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6816   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6817   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6818   multimap< int, int > nbInt2Axis; // to find the simplest case
6819   for ( int axis = 0; axis < nbAxes; ++axis )
6820   {
6821     gp_Ax1 lineAxis( point, axisDir[axis]);
6822     gp_Lin line    ( lineAxis );
6823
6824     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6825     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6826
6827     // Intersect faces with the line
6828
6829     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6830     TIDSortedElemSet::iterator face = suspectFaces.begin();
6831     for ( ; face != suspectFaces.end(); ++face )
6832     {
6833       // get face plane
6834       gp_XYZ fNorm;
6835       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6836       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6837
6838       // perform intersection
6839       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6840       if ( !intersection.IsDone() )
6841         continue;
6842       if ( intersection.IsInQuadric() )
6843       {
6844         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6845       }
6846       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6847       {
6848         gp_Pnt intersectionPoint = intersection.Point(1);
6849         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6850           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6851       }
6852     }
6853     // Analyse intersections roughly
6854
6855     int nbInter = u2inters.size();
6856     if ( nbInter == 0 )
6857       return TopAbs_OUT; 
6858
6859     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6860     if ( nbInter == 1 ) // not closed mesh
6861       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6862
6863     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6864       return TopAbs_ON;
6865
6866     if ( (f<0) == (l<0) )
6867       return TopAbs_OUT;
6868
6869     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6870     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6871     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6872       return TopAbs_IN;
6873
6874     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6875
6876     if ( _outerFacesFound ) break; // pass to thorough analysis
6877
6878   } // three attempts - loop on CS axes
6879
6880   // Analyse intersections thoroughly.
6881   // We make two loops maximum, on the first one we only exclude touching intersections,
6882   // on the second, if situation is still unclear, we gather and use information on
6883   // position of faces (internal or outer). If faces position is already gathered,
6884   // we make the second loop right away.
6885
6886   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6887   {
6888     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6889     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6890     {
6891       int axis = nb_axis->second;
6892       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6893
6894       gp_Ax1 lineAxis( point, axisDir[axis]);
6895       gp_Lin line    ( lineAxis );
6896
6897       // add tangent intersections to u2inters
6898       double param;
6899       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6900       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6901         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6902           u2inters.insert(make_pair( param, *tgtInt ));
6903       tangentInters[ axis ].clear();
6904
6905       // Count intersections before and after the point excluding touching ones.
6906       // If hasPositionInfo we count intersections of outer boundary only
6907
6908       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6909       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6910       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6911       bool ok = ! u_int1->second._coincides;
6912       while ( ok && u_int1 != u2inters.end() )
6913       {
6914         double u = u_int1->first;
6915         bool touchingInt = false;
6916         if ( ++u_int2 != u2inters.end() )
6917         {
6918           // skip intersections at the same point (if the line passes through edge or node)
6919           int nbSamePnt = 0;
6920           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6921           {
6922             ++nbSamePnt;
6923             ++u_int2;
6924           }
6925
6926           // skip tangent intersections
6927           int nbTgt = 0;
6928           const SMDS_MeshElement* prevFace = u_int1->second._face;
6929           while ( ok && u_int2->second._coincides )
6930           {
6931             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6932               ok = false;
6933             else
6934             {
6935               nbTgt++;
6936               u_int2++;
6937               ok = ( u_int2 != u2inters.end() );
6938             }
6939           }
6940           if ( !ok ) break;
6941
6942           // skip intersections at the same point after tangent intersections
6943           if ( nbTgt > 0 )
6944           {
6945             double u2 = u_int2->first;
6946             ++u_int2;
6947             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6948             {
6949               ++nbSamePnt;
6950               ++u_int2;
6951             }
6952           }
6953           // decide if we skipped a touching intersection
6954           if ( nbSamePnt + nbTgt > 0 )
6955           {
6956             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6957             map< double, TInters >::iterator u_int = u_int1;
6958             for ( ; u_int != u_int2; ++u_int )
6959             {
6960               if ( u_int->second._coincides ) continue;
6961               double dot = u_int->second._faceNorm * line.Direction();
6962               if ( dot > maxDot ) maxDot = dot;
6963               if ( dot < minDot ) minDot = dot;
6964             }
6965             touchingInt = ( minDot*maxDot < 0 );
6966           }
6967         }
6968         if ( !touchingInt )
6969         {
6970           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6971           {
6972             if ( u < 0 )
6973               ++nbIntBeforePoint;
6974             else
6975               ++nbIntAfterPoint;
6976           }
6977           if ( u < f ) f = u;
6978           if ( u > l ) l = u;
6979         }
6980
6981         u_int1 = u_int2; // to next intersection
6982
6983       } // loop on intersections with one line
6984
6985       if ( ok )
6986       {
6987         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6988           return TopAbs_ON;
6989
6990         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6991           return TopAbs_OUT; 
6992
6993         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6994           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6995
6996         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6997           return TopAbs_IN;
6998
6999         if ( (f<0) == (l<0) )
7000           return TopAbs_OUT;
7001
7002         if ( hasPositionInfo )
7003           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7004       }
7005     } // loop on intersections of the tree lines - thorough analysis
7006
7007     if ( !hasPositionInfo )
7008     {
7009       // gather info on faces position - is face in the outer boundary or not
7010       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7011       findOuterBoundary( u2inters.begin()->second._face );
7012     }
7013
7014   } // two attempts - with and w/o faces position info in the mesh
7015
7016   return TopAbs_UNKNOWN;
7017 }
7018
7019 //=======================================================================
7020 /*!
7021  * \brief Return elements possibly intersecting the line
7022  */
7023 //=======================================================================
7024
7025 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7026                                                      SMDSAbs_ElementType                type,
7027                                                      vector< const SMDS_MeshElement* >& foundElems)
7028 {
7029   if ( !_ebbTree || _elementType != type )
7030   {
7031     if ( _ebbTree ) delete _ebbTree;
7032     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7033   }
7034   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7035   _ebbTree->getElementsNearLine( line, suspectFaces );
7036   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7037 }
7038
7039 //=======================================================================
7040 /*!
7041  * \brief Return SMESH_ElementSearcher
7042  */
7043 //=======================================================================
7044
7045 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7046 {
7047   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7048 }
7049
7050 //=======================================================================
7051 /*!
7052  * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
7053  */
7054 //=======================================================================
7055
7056 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7057 {
7058   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7059 }
7060
7061 //=======================================================================
7062 /*!
7063  * \brief Return true if the point is IN or ON of the element
7064  */
7065 //=======================================================================
7066
7067 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7068 {
7069   if ( element->GetType() == SMDSAbs_Volume)
7070   {
7071     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7072   }
7073
7074   // get ordered nodes
7075
7076   vector< gp_XYZ > xyz;
7077   vector<const SMDS_MeshNode*> nodeList;
7078
7079   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7080   if ( element->IsQuadratic() ) {
7081     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7082       nodeIt = f->interlacedNodesElemIterator();
7083     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7084       nodeIt = e->interlacedNodesElemIterator();
7085   }
7086   while ( nodeIt->more() )
7087     {
7088       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7089       xyz.push_back( SMESH_TNodeXYZ(node) );
7090       nodeList.push_back(node);
7091     }
7092
7093   int i, nbNodes = element->NbNodes();
7094
7095   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7096   {
7097     // compute face normal
7098     gp_Vec faceNorm(0,0,0);
7099     xyz.push_back( xyz.front() );
7100     nodeList.push_back( nodeList.front() );
7101     for ( i = 0; i < nbNodes; ++i )
7102     {
7103       gp_Vec edge1( xyz[i+1], xyz[i]);
7104       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7105       faceNorm += edge1 ^ edge2;
7106     }
7107     double normSize = faceNorm.Magnitude();
7108     if ( normSize <= tol )
7109     {
7110       // degenerated face: point is out if it is out of all face edges
7111       for ( i = 0; i < nbNodes; ++i )
7112       {
7113         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7114         if ( !isOut( &edge, point, tol ))
7115           return false;
7116       }
7117       return true;
7118     }
7119     faceNorm /= normSize;
7120
7121     // check if the point lays on face plane
7122     gp_Vec n2p( xyz[0], point );
7123     if ( fabs( n2p * faceNorm ) > tol )
7124       return true; // not on face plane
7125
7126     // check if point is out of face boundary:
7127     // define it by closest transition of a ray point->infinity through face boundary
7128     // on the face plane.
7129     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7130     // to find intersections of the ray with the boundary.
7131     gp_Vec ray = n2p;
7132     gp_Vec plnNorm = ray ^ faceNorm;
7133     normSize = plnNorm.Magnitude();
7134     if ( normSize <= tol ) return false; // point coincides with the first node
7135     plnNorm /= normSize;
7136     // for each node of the face, compute its signed distance to the plane
7137     vector<double> dist( nbNodes + 1);
7138     for ( i = 0; i < nbNodes; ++i )
7139     {
7140       gp_Vec n2p( xyz[i], point );
7141       dist[i] = n2p * plnNorm;
7142     }
7143     dist.back() = dist.front();
7144     // find the closest intersection
7145     int    iClosest = -1;
7146     double rClosest, distClosest = 1e100;;
7147     gp_Pnt pClosest;
7148     for ( i = 0; i < nbNodes; ++i )
7149     {
7150       double r;
7151       if ( fabs( dist[i]) < tol )
7152         r = 0.;
7153       else if ( fabs( dist[i+1]) < tol )
7154         r = 1.;
7155       else if ( dist[i] * dist[i+1] < 0 )
7156         r = dist[i] / ( dist[i] - dist[i+1] );
7157       else
7158         continue; // no intersection
7159       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7160       gp_Vec p2int ( point, pInt);
7161       if ( p2int * ray > -tol ) // right half-space
7162       {
7163         double intDist = p2int.SquareMagnitude();
7164         if ( intDist < distClosest )
7165         {
7166           iClosest = i;
7167           rClosest = r;
7168           pClosest = pInt;
7169           distClosest = intDist;
7170         }
7171       }
7172     }
7173     if ( iClosest < 0 )
7174       return true; // no intesections - out
7175
7176     // analyse transition
7177     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7178     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7179     gp_Vec p2int ( point, pClosest );
7180     bool out = (edgeNorm * p2int) < -tol;
7181     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7182       return out;
7183
7184     // ray pass through a face node; analyze transition through an adjacent edge
7185     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7186     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7187     gp_Vec edgeAdjacent( p1, p2 );
7188     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7189     bool out2 = (edgeNorm2 * p2int) < -tol;
7190
7191     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7192     return covexCorner ? (out || out2) : (out && out2);
7193   }
7194   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7195   {
7196     // point is out of edge if it is NOT ON any straight part of edge
7197     // (we consider quadratic edge as being composed of two straight parts)
7198     for ( i = 1; i < nbNodes; ++i )
7199     {
7200       gp_Vec edge( xyz[i-1], xyz[i]);
7201       gp_Vec n1p ( xyz[i-1], point);
7202       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7203       if ( dist > tol )
7204         continue;
7205       gp_Vec n2p( xyz[i], point );
7206       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7207         continue;
7208       return false; // point is ON this part
7209     }
7210     return true;
7211   }
7212   // Node or 0D element -------------------------------------------------------------------------
7213   {
7214     gp_Vec n2p ( xyz[0], point );
7215     return n2p.Magnitude() <= tol;
7216   }
7217   return true;
7218 }
7219
7220 //=======================================================================
7221 //function : SimplifyFace
7222 //purpose  :
7223 //=======================================================================
7224 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7225                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7226                                     vector<int>&                        quantities) const
7227 {
7228   int nbNodes = faceNodes.size();
7229
7230   if (nbNodes < 3)
7231     return 0;
7232
7233   set<const SMDS_MeshNode*> nodeSet;
7234
7235   // get simple seq of nodes
7236   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7237   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7238   int iSimple = 0, nbUnique = 0;
7239
7240   simpleNodes[iSimple++] = faceNodes[0];
7241   nbUnique++;
7242   for (int iCur = 1; iCur < nbNodes; iCur++) {
7243     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7244       simpleNodes[iSimple++] = faceNodes[iCur];
7245       if (nodeSet.insert( faceNodes[iCur] ).second)
7246         nbUnique++;
7247     }
7248   }
7249   int nbSimple = iSimple;
7250   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7251     nbSimple--;
7252     iSimple--;
7253   }
7254
7255   if (nbUnique < 3)
7256     return 0;
7257
7258   // separate loops
7259   int nbNew = 0;
7260   bool foundLoop = (nbSimple > nbUnique);
7261   while (foundLoop) {
7262     foundLoop = false;
7263     set<const SMDS_MeshNode*> loopSet;
7264     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7265       const SMDS_MeshNode* n = simpleNodes[iSimple];
7266       if (!loopSet.insert( n ).second) {
7267         foundLoop = true;
7268
7269         // separate loop
7270         int iC = 0, curLast = iSimple;
7271         for (; iC < curLast; iC++) {
7272           if (simpleNodes[iC] == n) break;
7273         }
7274         int loopLen = curLast - iC;
7275         if (loopLen > 2) {
7276           // create sub-element
7277           nbNew++;
7278           quantities.push_back(loopLen);
7279           for (; iC < curLast; iC++) {
7280             poly_nodes.push_back(simpleNodes[iC]);
7281           }
7282         }
7283         // shift the rest nodes (place from the first loop position)
7284         for (iC = curLast + 1; iC < nbSimple; iC++) {
7285           simpleNodes[iC - loopLen] = simpleNodes[iC];
7286         }
7287         nbSimple -= loopLen;
7288         iSimple -= loopLen;
7289       }
7290     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7291   } // while (foundLoop)
7292
7293   if (iSimple > 2) {
7294     nbNew++;
7295     quantities.push_back(iSimple);
7296     for (int i = 0; i < iSimple; i++)
7297       poly_nodes.push_back(simpleNodes[i]);
7298   }
7299
7300   return nbNew;
7301 }
7302
7303 //=======================================================================
7304 //function : MergeNodes
7305 //purpose  : In each group, the cdr of nodes are substituted by the first one
7306 //           in all elements.
7307 //=======================================================================
7308
7309 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7310 {
7311   MESSAGE("MergeNodes");
7312   myLastCreatedElems.Clear();
7313   myLastCreatedNodes.Clear();
7314
7315   SMESHDS_Mesh* aMesh = GetMeshDS();
7316
7317   TNodeNodeMap nodeNodeMap; // node to replace - new node
7318   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7319   list< int > rmElemIds, rmNodeIds;
7320
7321   // Fill nodeNodeMap and elems
7322
7323   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7324   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7325     list<const SMDS_MeshNode*>& nodes = *grIt;
7326     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7327     const SMDS_MeshNode* nToKeep = *nIt;
7328     //MESSAGE("node to keep " << nToKeep->GetID());
7329     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7330       const SMDS_MeshNode* nToRemove = *nIt;
7331       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7332       if ( nToRemove != nToKeep ) {
7333         //MESSAGE("  node to remove " << nToRemove->GetID());
7334         rmNodeIds.push_back( nToRemove->GetID() );
7335         AddToSameGroups( nToKeep, nToRemove, aMesh );
7336       }
7337
7338       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7339       while ( invElemIt->more() ) {
7340         const SMDS_MeshElement* elem = invElemIt->next();
7341         elems.insert(elem);
7342       }
7343     }
7344   }
7345   // Change element nodes or remove an element
7346
7347   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7348   for ( ; eIt != elems.end(); eIt++ ) {
7349     const SMDS_MeshElement* elem = *eIt;
7350     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7351     int nbNodes = elem->NbNodes();
7352     int aShapeId = FindShape( elem );
7353
7354     set<const SMDS_MeshNode*> nodeSet;
7355     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7356     int iUnique = 0, iCur = 0, nbRepl = 0;
7357     vector<int> iRepl( nbNodes );
7358
7359     // get new seq of nodes
7360     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7361     while ( itN->more() ) {
7362       const SMDS_MeshNode* n =
7363         static_cast<const SMDS_MeshNode*>( itN->next() );
7364
7365       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7366       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7367         n = (*nnIt).second;
7368         // BUG 0020185: begin
7369         {
7370           bool stopRecur = false;
7371           set<const SMDS_MeshNode*> nodesRecur;
7372           nodesRecur.insert(n);
7373           while (!stopRecur) {
7374             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7375             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7376               n = (*nnIt_i).second;
7377               if (!nodesRecur.insert(n).second) {
7378                 // error: recursive dependancy
7379                 stopRecur = true;
7380               }
7381             }
7382             else
7383               stopRecur = true;
7384           }
7385         }
7386         // BUG 0020185: end
7387         iRepl[ nbRepl++ ] = iCur;
7388       }
7389       curNodes[ iCur ] = n;
7390       bool isUnique = nodeSet.insert( n ).second;
7391       if ( isUnique ) {
7392         uniqueNodes[ iUnique++ ] = n;
7393         if ( nbRepl && iRepl[ nbRepl-1 ] == iCur )
7394           --nbRepl; // n do not stick to a node of the elem
7395       }
7396       iCur++;
7397     }
7398
7399     // Analyse element topology after replacement
7400
7401     bool isOk = true;
7402     int nbUniqueNodes = nodeSet.size();
7403     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7404     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7405       // Polygons and Polyhedral volumes
7406       if (elem->IsPoly()) {
7407
7408         if (elem->GetType() == SMDSAbs_Face) {
7409           // Polygon
7410           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7411           int inode = 0;
7412           for (; inode < nbNodes; inode++) {
7413             face_nodes[inode] = curNodes[inode];
7414           }
7415
7416           vector<const SMDS_MeshNode *> polygons_nodes;
7417           vector<int> quantities;
7418           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7419           if (nbNew > 0) {
7420             inode = 0;
7421             for (int iface = 0; iface < nbNew; iface++) {
7422               int nbNodes = quantities[iface];
7423               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7424               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7425                 poly_nodes[ii] = polygons_nodes[inode];
7426               }
7427               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7428               myLastCreatedElems.Append(newElem);
7429               if (aShapeId)
7430                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7431             }
7432
7433             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7434             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7435             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7436             int quid =0;
7437             if (nbNew > 0) quid = nbNew - 1;
7438             vector<int> newquant(quantities.begin()+quid, quantities.end());
7439             const SMDS_MeshElement* newElem = 0;
7440             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7441             myLastCreatedElems.Append(newElem);
7442             if ( aShapeId && newElem )
7443               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7444             rmElemIds.push_back(elem->GetID());
7445           }
7446           else {
7447             rmElemIds.push_back(elem->GetID());
7448           }
7449
7450         }
7451         else if (elem->GetType() == SMDSAbs_Volume) {
7452           // Polyhedral volume
7453           if (nbUniqueNodes < 4) {
7454             rmElemIds.push_back(elem->GetID());
7455           }
7456           else {
7457             // each face has to be analyzed in order to check volume validity
7458             const SMDS_VtkVolume* aPolyedre =
7459               dynamic_cast<const SMDS_VtkVolume*>( elem );
7460             if (aPolyedre) {
7461               int nbFaces = aPolyedre->NbFaces();
7462
7463               vector<const SMDS_MeshNode *> poly_nodes;
7464               vector<int> quantities;
7465
7466               for (int iface = 1; iface <= nbFaces; iface++) {
7467                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7468                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7469
7470                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7471                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7472                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7473                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7474                     faceNode = (*nnIt).second;
7475                   }
7476                   faceNodes[inode - 1] = faceNode;
7477                 }
7478
7479                 SimplifyFace(faceNodes, poly_nodes, quantities);
7480               }
7481
7482               if (quantities.size() > 3) {
7483                 // to be done: remove coincident faces
7484               }
7485
7486               if (quantities.size() > 3)
7487                 {
7488                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7489                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7490                   const SMDS_MeshElement* newElem = 0;
7491                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7492                   myLastCreatedElems.Append(newElem);
7493                   if ( aShapeId && newElem )
7494                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7495                   rmElemIds.push_back(elem->GetID());
7496                 }
7497             }
7498             else {
7499               rmElemIds.push_back(elem->GetID());
7500             }
7501           }
7502         }
7503         else {
7504         }
7505
7506         continue;
7507       } // poly element
7508
7509       // Regular elements
7510       // TODO not all the possible cases are solved. Find something more generic?
7511       switch ( nbNodes ) {
7512       case 2: ///////////////////////////////////// EDGE
7513         isOk = false; break;
7514       case 3: ///////////////////////////////////// TRIANGLE
7515         isOk = false; break;
7516       case 4:
7517         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7518           isOk = false;
7519         else { //////////////////////////////////// QUADRANGLE
7520           if ( nbUniqueNodes < 3 )
7521             isOk = false;
7522           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7523             isOk = false; // opposite nodes stick
7524           //MESSAGE("isOk " << isOk);
7525         }
7526         break;
7527       case 6: ///////////////////////////////////// PENTAHEDRON
7528         if ( nbUniqueNodes == 4 ) {
7529           // ---------------------------------> tetrahedron
7530           if (nbRepl == 3 &&
7531               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7532             // all top nodes stick: reverse a bottom
7533             uniqueNodes[ 0 ] = curNodes [ 1 ];
7534             uniqueNodes[ 1 ] = curNodes [ 0 ];
7535           }
7536           else if (nbRepl == 3 &&
7537                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7538             // all bottom nodes stick: set a top before
7539             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7540             uniqueNodes[ 0 ] = curNodes [ 3 ];
7541             uniqueNodes[ 1 ] = curNodes [ 4 ];
7542             uniqueNodes[ 2 ] = curNodes [ 5 ];
7543           }
7544           else if (nbRepl == 4 &&
7545                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7546             // a lateral face turns into a line: reverse a bottom
7547             uniqueNodes[ 0 ] = curNodes [ 1 ];
7548             uniqueNodes[ 1 ] = curNodes [ 0 ];
7549           }
7550           else
7551             isOk = false;
7552         }
7553         else if ( nbUniqueNodes == 5 ) {
7554           // PENTAHEDRON --------------------> 2 tetrahedrons
7555           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7556             // a bottom node sticks with a linked top one
7557             // 1.
7558             SMDS_MeshElement* newElem =
7559               aMesh->AddVolume(curNodes[ 3 ],
7560                                curNodes[ 4 ],
7561                                curNodes[ 5 ],
7562                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7563             myLastCreatedElems.Append(newElem);
7564             if ( aShapeId )
7565               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7566             // 2. : reverse a bottom
7567             uniqueNodes[ 0 ] = curNodes [ 1 ];
7568             uniqueNodes[ 1 ] = curNodes [ 0 ];
7569             nbUniqueNodes = 4;
7570           }
7571           else
7572             isOk = false;
7573         }
7574         else
7575           isOk = false;
7576         break;
7577       case 8: {
7578         if(elem->IsQuadratic()) { // Quadratic quadrangle
7579           //   1    5    2
7580           //    +---+---+
7581           //    |       |
7582           //    |       |
7583           //   4+       +6
7584           //    |       |
7585           //    |       |
7586           //    +---+---+
7587           //   0    7    3
7588           isOk = false;
7589           if(nbRepl==2) {
7590             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7591           }
7592           if(nbRepl==3) {
7593             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7594             nbUniqueNodes = 6;
7595             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7596               uniqueNodes[0] = curNodes[0];
7597               uniqueNodes[1] = curNodes[2];
7598               uniqueNodes[2] = curNodes[3];
7599               uniqueNodes[3] = curNodes[5];
7600               uniqueNodes[4] = curNodes[6];
7601               uniqueNodes[5] = curNodes[7];
7602               isOk = true;
7603             }
7604             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7605               uniqueNodes[0] = curNodes[0];
7606               uniqueNodes[1] = curNodes[1];
7607               uniqueNodes[2] = curNodes[2];
7608               uniqueNodes[3] = curNodes[4];
7609               uniqueNodes[4] = curNodes[5];
7610               uniqueNodes[5] = curNodes[6];
7611               isOk = true;
7612             }
7613             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7614               uniqueNodes[0] = curNodes[1];
7615               uniqueNodes[1] = curNodes[2];
7616               uniqueNodes[2] = curNodes[3];
7617               uniqueNodes[3] = curNodes[5];
7618               uniqueNodes[4] = curNodes[6];
7619               uniqueNodes[5] = curNodes[0];
7620               isOk = true;
7621             }
7622             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7623               uniqueNodes[0] = curNodes[0];
7624               uniqueNodes[1] = curNodes[1];
7625               uniqueNodes[2] = curNodes[3];
7626               uniqueNodes[3] = curNodes[4];
7627               uniqueNodes[4] = curNodes[6];
7628               uniqueNodes[5] = curNodes[7];
7629               isOk = true;
7630             }
7631             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7632               uniqueNodes[0] = curNodes[0];
7633               uniqueNodes[1] = curNodes[2];
7634               uniqueNodes[2] = curNodes[3];
7635               uniqueNodes[3] = curNodes[1];
7636               uniqueNodes[4] = curNodes[6];
7637               uniqueNodes[5] = curNodes[7];
7638               isOk = true;
7639             }
7640             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7641               uniqueNodes[0] = curNodes[0];
7642               uniqueNodes[1] = curNodes[1];
7643               uniqueNodes[2] = curNodes[2];
7644               uniqueNodes[3] = curNodes[4];
7645               uniqueNodes[4] = curNodes[5];
7646               uniqueNodes[5] = curNodes[7];
7647               isOk = true;
7648             }
7649             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7650               uniqueNodes[0] = curNodes[0];
7651               uniqueNodes[1] = curNodes[1];
7652               uniqueNodes[2] = curNodes[3];
7653               uniqueNodes[3] = curNodes[4];
7654               uniqueNodes[4] = curNodes[2];
7655               uniqueNodes[5] = curNodes[7];
7656               isOk = true;
7657             }
7658             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7659               uniqueNodes[0] = curNodes[0];
7660               uniqueNodes[1] = curNodes[1];
7661               uniqueNodes[2] = curNodes[2];
7662               uniqueNodes[3] = curNodes[4];
7663               uniqueNodes[4] = curNodes[5];
7664               uniqueNodes[5] = curNodes[3];
7665               isOk = true;
7666             }
7667           }
7668           if(nbRepl==4) {
7669             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7670           }
7671           if(nbRepl==5) {
7672             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7673           }
7674           break;
7675         }
7676         //////////////////////////////////// HEXAHEDRON
7677         isOk = false;
7678         SMDS_VolumeTool hexa (elem);
7679         hexa.SetExternalNormal();
7680         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7681           //////////////////////// HEX ---> 1 tetrahedron
7682           for ( int iFace = 0; iFace < 6; iFace++ ) {
7683             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7684             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7685                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7686                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7687               // one face turns into a point ...
7688               int iOppFace = hexa.GetOppFaceIndex( iFace );
7689               ind = hexa.GetFaceNodesIndices( iOppFace );
7690               int nbStick = 0;
7691               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7692                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7693                   nbStick++;
7694               }
7695               if ( nbStick == 1 ) {
7696                 // ... and the opposite one - into a triangle.
7697                 // set a top node
7698                 ind = hexa.GetFaceNodesIndices( iFace );
7699                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7700                 isOk = true;
7701               }
7702               break;
7703             }
7704           }
7705         }
7706         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7707           //////////////////////// HEX ---> 1 prism
7708           int nbTria = 0, iTria[3];
7709           const int *ind; // indices of face nodes
7710           // look for triangular faces
7711           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7712             ind = hexa.GetFaceNodesIndices( iFace );
7713             TIDSortedNodeSet faceNodes;
7714             for ( iCur = 0; iCur < 4; iCur++ )
7715               faceNodes.insert( curNodes[ind[iCur]] );
7716             if ( faceNodes.size() == 3 )
7717               iTria[ nbTria++ ] = iFace;
7718           }
7719           // check if triangles are opposite
7720           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7721           {
7722             isOk = true;
7723             // set nodes of the bottom triangle
7724             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7725             vector<int> indB;
7726             for ( iCur = 0; iCur < 4; iCur++ )
7727               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7728                 indB.push_back( ind[iCur] );
7729             if ( !hexa.IsForward() )
7730               std::swap( indB[0], indB[2] );
7731             for ( iCur = 0; iCur < 3; iCur++ )
7732               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7733             // set nodes of the top triangle
7734             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7735             for ( iCur = 0; iCur < 3; ++iCur )
7736               for ( int j = 0; j < 4; ++j )
7737                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7738                 {
7739                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7740                   break;
7741                 }
7742           }
7743           break;
7744         }
7745         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7746           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7747           for ( int iFace = 0; iFace < 6; iFace++ ) {
7748             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7749             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7750                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7751                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7752               // one face turns into a point ...
7753               int iOppFace = hexa.GetOppFaceIndex( iFace );
7754               ind = hexa.GetFaceNodesIndices( iOppFace );
7755               int nbStick = 0;
7756               iUnique = 2;  // reverse a tetrahedron 1 bottom
7757               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7758                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7759                   nbStick++;
7760                 else if ( iUnique >= 0 )
7761                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7762               }
7763               if ( nbStick == 0 ) {
7764                 // ... and the opposite one is a quadrangle
7765                 // set a top node
7766                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7767                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7768                 nbUniqueNodes = 4;
7769                 // tetrahedron 2
7770                 SMDS_MeshElement* newElem =
7771                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7772                                    curNodes[ind[ 3 ]],
7773                                    curNodes[ind[ 2 ]],
7774                                    curNodes[indTop[ 0 ]]);
7775                 myLastCreatedElems.Append(newElem);
7776                 if ( aShapeId )
7777                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7778                 isOk = true;
7779               }
7780               break;
7781             }
7782           }
7783         }
7784         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7785           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7786           // find indices of quad and tri faces
7787           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7788           for ( iFace = 0; iFace < 6; iFace++ ) {
7789             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7790             nodeSet.clear();
7791             for ( iCur = 0; iCur < 4; iCur++ )
7792               nodeSet.insert( curNodes[ind[ iCur ]] );
7793             nbUniqueNodes = nodeSet.size();
7794             if ( nbUniqueNodes == 3 )
7795               iTriFace[ nbTri++ ] = iFace;
7796             else if ( nbUniqueNodes == 4 )
7797               iQuadFace[ nbQuad++ ] = iFace;
7798           }
7799           if (nbQuad == 2 && nbTri == 4 &&
7800               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7801             // 2 opposite quadrangles stuck with a diagonal;
7802             // sample groups of merged indices: (0-4)(2-6)
7803             // --------------------------------------------> 2 tetrahedrons
7804             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7805             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7806             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7807             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7808                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7809               // stuck with 0-2 diagonal
7810               i0  = ind1[ 3 ];
7811               i1d = ind1[ 0 ];
7812               i2  = ind1[ 1 ];
7813               i3d = ind1[ 2 ];
7814               i0t = ind2[ 1 ];
7815               i2t = ind2[ 3 ];
7816             }
7817             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7818                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7819               // stuck with 1-3 diagonal
7820               i0  = ind1[ 0 ];
7821               i1d = ind1[ 1 ];
7822               i2  = ind1[ 2 ];
7823               i3d = ind1[ 3 ];
7824               i0t = ind2[ 0 ];
7825               i2t = ind2[ 1 ];
7826             }
7827             else {
7828               ASSERT(0);
7829             }
7830             // tetrahedron 1
7831             uniqueNodes[ 0 ] = curNodes [ i0 ];
7832             uniqueNodes[ 1 ] = curNodes [ i1d ];
7833             uniqueNodes[ 2 ] = curNodes [ i3d ];
7834             uniqueNodes[ 3 ] = curNodes [ i0t ];
7835             nbUniqueNodes = 4;
7836             // tetrahedron 2
7837             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7838                                                          curNodes[ i2 ],
7839                                                          curNodes[ i3d ],
7840                                                          curNodes[ i2t ]);
7841             myLastCreatedElems.Append(newElem);
7842             if ( aShapeId )
7843               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7844             isOk = true;
7845           }
7846           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7847                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7848             // --------------------------------------------> prism
7849             // find 2 opposite triangles
7850             nbUniqueNodes = 6;
7851             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7852               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7853                 // find indices of kept and replaced nodes
7854                 // and fill unique nodes of 2 opposite triangles
7855                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7856                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7857                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7858                 // fill unique nodes
7859                 iUnique = 0;
7860                 isOk = true;
7861                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7862                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7863                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7864                   if ( n == nInit ) {
7865                     // iCur of a linked node of the opposite face (make normals co-directed):
7866                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7867                     // check that correspondent corners of triangles are linked
7868                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7869                       isOk = false;
7870                     else {
7871                       uniqueNodes[ iUnique ] = n;
7872                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7873                       iUnique++;
7874                     }
7875                   }
7876                 }
7877                 break;
7878               }
7879             }
7880           }
7881         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7882         else
7883         {
7884           MESSAGE("MergeNodes() removes hexahedron "<< elem);
7885         }
7886         break;
7887       } // HEXAHEDRON
7888
7889       default:
7890         isOk = false;
7891       } // switch ( nbNodes )
7892
7893     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7894
7895     if ( isOk ) { // the elem remains valid after sticking nodes
7896       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
7897       {
7898         // Change nodes of polyedre
7899         const SMDS_VtkVolume* aPolyedre =
7900           dynamic_cast<const SMDS_VtkVolume*>( elem );
7901         if (aPolyedre) {
7902           int nbFaces = aPolyedre->NbFaces();
7903
7904           vector<const SMDS_MeshNode *> poly_nodes;
7905           vector<int> quantities (nbFaces);
7906
7907           for (int iface = 1; iface <= nbFaces; iface++) {
7908             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7909             quantities[iface - 1] = nbFaceNodes;
7910
7911             for (inode = 1; inode <= nbFaceNodes; inode++) {
7912               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7913
7914               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7915               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7916                 curNode = (*nnIt).second;
7917               }
7918               poly_nodes.push_back(curNode);
7919             }
7920           }
7921           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7922         }
7923       }
7924       else // replace non-polyhedron elements
7925       {
7926         const SMDSAbs_ElementType etyp = elem->GetType();
7927         const int elemId               = elem->GetID();
7928         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
7929         uniqueNodes.resize(nbUniqueNodes);
7930
7931         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
7932
7933         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7934         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
7935         if ( sm && newElem )
7936           sm->AddElement( newElem );
7937         if ( elem != newElem )
7938           ReplaceElemInGroups( elem, newElem, aMesh );
7939       }
7940     }
7941     else {
7942       // Remove invalid regular element or invalid polygon
7943       rmElemIds.push_back( elem->GetID() );
7944     }
7945
7946   } // loop on elements
7947
7948   // Remove bad elements, then equal nodes (order important)
7949
7950   Remove( rmElemIds, false );
7951   Remove( rmNodeIds, true );
7952
7953 }
7954
7955
7956 // ========================================================
7957 // class   : SortableElement
7958 // purpose : allow sorting elements basing on their nodes
7959 // ========================================================
7960 class SortableElement : public set <const SMDS_MeshElement*>
7961 {
7962 public:
7963
7964   SortableElement( const SMDS_MeshElement* theElem )
7965   {
7966     myElem = theElem;
7967     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7968     while ( nodeIt->more() )
7969       this->insert( nodeIt->next() );
7970   }
7971
7972   const SMDS_MeshElement* Get() const
7973   { return myElem; }
7974
7975   void Set(const SMDS_MeshElement* e) const
7976   { myElem = e; }
7977
7978
7979 private:
7980   mutable const SMDS_MeshElement* myElem;
7981 };
7982
7983 //=======================================================================
7984 //function : FindEqualElements
7985 //purpose  : Return list of group of elements built on the same nodes.
7986 //           Search among theElements or in the whole mesh if theElements is empty
7987 //=======================================================================
7988 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7989                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7990 {
7991   myLastCreatedElems.Clear();
7992   myLastCreatedNodes.Clear();
7993
7994   typedef set<const SMDS_MeshElement*> TElemsSet;
7995   typedef map< SortableElement, int > TMapOfNodeSet;
7996   typedef list<int> TGroupOfElems;
7997
7998   TElemsSet elems;
7999   if ( theElements.empty() )
8000   { // get all elements in the mesh
8001     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
8002     while ( eIt->more() )
8003       elems.insert( elems.end(), eIt->next());
8004   }
8005   else
8006     elems = theElements;
8007
8008   vector< TGroupOfElems > arrayOfGroups;
8009   TGroupOfElems groupOfElems;
8010   TMapOfNodeSet mapOfNodeSet;
8011
8012   TElemsSet::iterator elemIt = elems.begin();
8013   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
8014     const SMDS_MeshElement* curElem = *elemIt;
8015     SortableElement SE(curElem);
8016     int ind = -1;
8017     // check uniqueness
8018     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
8019     if( !(pp.second) ) {
8020       TMapOfNodeSet::iterator& itSE = pp.first;
8021       ind = (*itSE).second;
8022       arrayOfGroups[ind].push_back(curElem->GetID());
8023     }
8024     else {
8025       groupOfElems.clear();
8026       groupOfElems.push_back(curElem->GetID());
8027       arrayOfGroups.push_back(groupOfElems);
8028       i++;
8029     }
8030   }
8031
8032   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
8033   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8034     groupOfElems = *groupIt;
8035     if ( groupOfElems.size() > 1 ) {
8036       groupOfElems.sort();
8037       theGroupsOfElementsID.push_back(groupOfElems);
8038     }
8039   }
8040 }
8041
8042 //=======================================================================
8043 //function : MergeElements
8044 //purpose  : In each given group, substitute all elements by the first one.
8045 //=======================================================================
8046
8047 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8048 {
8049   myLastCreatedElems.Clear();
8050   myLastCreatedNodes.Clear();
8051
8052   typedef list<int> TListOfIDs;
8053   TListOfIDs rmElemIds; // IDs of elems to remove
8054
8055   SMESHDS_Mesh* aMesh = GetMeshDS();
8056
8057   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8058   while ( groupsIt != theGroupsOfElementsID.end() ) {
8059     TListOfIDs& aGroupOfElemID = *groupsIt;
8060     aGroupOfElemID.sort();
8061     int elemIDToKeep = aGroupOfElemID.front();
8062     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8063     aGroupOfElemID.pop_front();
8064     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8065     while ( idIt != aGroupOfElemID.end() ) {
8066       int elemIDToRemove = *idIt;
8067       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8068       // add the kept element in groups of removed one (PAL15188)
8069       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8070       rmElemIds.push_back( elemIDToRemove );
8071       ++idIt;
8072     }
8073     ++groupsIt;
8074   }
8075
8076   Remove( rmElemIds, false );
8077 }
8078
8079 //=======================================================================
8080 //function : MergeEqualElements
8081 //purpose  : Remove all but one of elements built on the same nodes.
8082 //=======================================================================
8083
8084 void SMESH_MeshEditor::MergeEqualElements()
8085 {
8086   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8087                                                  to merge equal elements in the whole mesh */
8088   TListOfListOfElementsID aGroupsOfElementsID;
8089   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8090   MergeElements(aGroupsOfElementsID);
8091 }
8092
8093 //=======================================================================
8094 //function : FindFaceInSet
8095 //purpose  : Return a face having linked nodes n1 and n2 and which is
8096 //           - not in avoidSet,
8097 //           - in elemSet provided that !elemSet.empty()
8098 //           i1 and i2 optionally returns indices of n1 and n2
8099 //=======================================================================
8100
8101 const SMDS_MeshElement*
8102 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8103                                 const SMDS_MeshNode*    n2,
8104                                 const TIDSortedElemSet& elemSet,
8105                                 const TIDSortedElemSet& avoidSet,
8106                                 int*                    n1ind,
8107                                 int*                    n2ind)
8108
8109 {
8110   int i1, i2;
8111   const SMDS_MeshElement* face = 0;
8112
8113   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8114   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8115   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8116   {
8117     //MESSAGE("in while ( invElemIt->more() && !face )");
8118     const SMDS_MeshElement* elem = invElemIt->next();
8119     if (avoidSet.count( elem ))
8120       continue;
8121     if ( !elemSet.empty() && !elemSet.count( elem ))
8122       continue;
8123     // index of n1
8124     i1 = elem->GetNodeIndex( n1 );
8125     // find a n2 linked to n1
8126     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8127     for ( int di = -1; di < 2 && !face; di += 2 )
8128     {
8129       i2 = (i1+di+nbN) % nbN;
8130       if ( elem->GetNode( i2 ) == n2 )
8131         face = elem;
8132     }
8133     if ( !face && elem->IsQuadratic())
8134     {
8135       // analysis for quadratic elements using all nodes
8136       const SMDS_VtkFace* F =
8137         dynamic_cast<const SMDS_VtkFace*>(elem);
8138       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8139       // use special nodes iterator
8140       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8141       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8142       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8143       {
8144         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8145         if ( n1 == prevN && n2 == n )
8146         {
8147           face = elem;
8148         }
8149         else if ( n2 == prevN && n1 == n )
8150         {
8151           face = elem; swap( i1, i2 );
8152         }
8153         prevN = n;
8154       }
8155     }
8156   }
8157   if ( n1ind ) *n1ind = i1;
8158   if ( n2ind ) *n2ind = i2;
8159   return face;
8160 }
8161
8162 //=======================================================================
8163 //function : findAdjacentFace
8164 //purpose  :
8165 //=======================================================================
8166
8167 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8168                                                 const SMDS_MeshNode* n2,
8169                                                 const SMDS_MeshElement* elem)
8170 {
8171   TIDSortedElemSet elemSet, avoidSet;
8172   if ( elem )
8173     avoidSet.insert ( elem );
8174   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8175 }
8176
8177 //=======================================================================
8178 //function : FindFreeBorder
8179 //purpose  :
8180 //=======================================================================
8181
8182 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8183
8184 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8185                                        const SMDS_MeshNode*             theSecondNode,
8186                                        const SMDS_MeshNode*             theLastNode,
8187                                        list< const SMDS_MeshNode* > &   theNodes,
8188                                        list< const SMDS_MeshElement* >& theFaces)
8189 {
8190   if ( !theFirstNode || !theSecondNode )
8191     return false;
8192   // find border face between theFirstNode and theSecondNode
8193   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8194   if ( !curElem )
8195     return false;
8196
8197   theFaces.push_back( curElem );
8198   theNodes.push_back( theFirstNode );
8199   theNodes.push_back( theSecondNode );
8200
8201   //vector<const SMDS_MeshNode*> nodes;
8202   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8203   TIDSortedElemSet foundElems;
8204   bool needTheLast = ( theLastNode != 0 );
8205
8206   while ( nStart != theLastNode ) {
8207     if ( nStart == theFirstNode )
8208       return !needTheLast;
8209
8210     // find all free border faces sharing form nStart
8211
8212     list< const SMDS_MeshElement* > curElemList;
8213     list< const SMDS_MeshNode* > nStartList;
8214     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8215     while ( invElemIt->more() ) {
8216       const SMDS_MeshElement* e = invElemIt->next();
8217       if ( e == curElem || foundElems.insert( e ).second ) {
8218         // get nodes
8219         int iNode = 0, nbNodes = e->NbNodes();
8220         //const SMDS_MeshNode* nodes[nbNodes+1];
8221         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8222
8223         if(e->IsQuadratic()) {
8224           const SMDS_VtkFace* F =
8225             dynamic_cast<const SMDS_VtkFace*>(e);
8226           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8227           // use special nodes iterator
8228           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8229           while( anIter->more() ) {
8230             nodes[ iNode++ ] = cast2Node(anIter->next());
8231           }
8232         }
8233         else {
8234           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8235           while ( nIt->more() )
8236             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8237         }
8238         nodes[ iNode ] = nodes[ 0 ];
8239         // check 2 links
8240         for ( iNode = 0; iNode < nbNodes; iNode++ )
8241           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8242                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8243               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8244           {
8245             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8246             curElemList.push_back( e );
8247           }
8248       }
8249     }
8250     // analyse the found
8251
8252     int nbNewBorders = curElemList.size();
8253     if ( nbNewBorders == 0 ) {
8254       // no free border furthermore
8255       return !needTheLast;
8256     }
8257     else if ( nbNewBorders == 1 ) {
8258       // one more element found
8259       nIgnore = nStart;
8260       nStart = nStartList.front();
8261       curElem = curElemList.front();
8262       theFaces.push_back( curElem );
8263       theNodes.push_back( nStart );
8264     }
8265     else {
8266       // several continuations found
8267       list< const SMDS_MeshElement* >::iterator curElemIt;
8268       list< const SMDS_MeshNode* >::iterator nStartIt;
8269       // check if one of them reached the last node
8270       if ( needTheLast ) {
8271         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8272              curElemIt!= curElemList.end();
8273              curElemIt++, nStartIt++ )
8274           if ( *nStartIt == theLastNode ) {
8275             theFaces.push_back( *curElemIt );
8276             theNodes.push_back( *nStartIt );
8277             return true;
8278           }
8279       }
8280       // find the best free border by the continuations
8281       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8282       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8283       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8284            curElemIt!= curElemList.end();
8285            curElemIt++, nStartIt++ )
8286       {
8287         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8288         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8289         // find one more free border
8290         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8291           cNL->clear();
8292           cFL->clear();
8293         }
8294         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8295           // choice: clear a worse one
8296           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8297           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8298           contNodes[ iWorse ].clear();
8299           contFaces[ iWorse ].clear();
8300         }
8301       }
8302       if ( contNodes[0].empty() && contNodes[1].empty() )
8303         return false;
8304
8305       // append the best free border
8306       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8307       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8308       theNodes.pop_back(); // remove nIgnore
8309       theNodes.pop_back(); // remove nStart
8310       theFaces.pop_back(); // remove curElem
8311       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8312       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8313       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8314       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8315       return true;
8316
8317     } // several continuations found
8318   } // while ( nStart != theLastNode )
8319
8320   return true;
8321 }
8322
8323 //=======================================================================
8324 //function : CheckFreeBorderNodes
8325 //purpose  : Return true if the tree nodes are on a free border
8326 //=======================================================================
8327
8328 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8329                                             const SMDS_MeshNode* theNode2,
8330                                             const SMDS_MeshNode* theNode3)
8331 {
8332   list< const SMDS_MeshNode* > nodes;
8333   list< const SMDS_MeshElement* > faces;
8334   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8335 }
8336
8337 //=======================================================================
8338 //function : SewFreeBorder
8339 //purpose  :
8340 //=======================================================================
8341
8342 SMESH_MeshEditor::Sew_Error
8343 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8344                                  const SMDS_MeshNode* theBordSecondNode,
8345                                  const SMDS_MeshNode* theBordLastNode,
8346                                  const SMDS_MeshNode* theSideFirstNode,
8347                                  const SMDS_MeshNode* theSideSecondNode,
8348                                  const SMDS_MeshNode* theSideThirdNode,
8349                                  const bool           theSideIsFreeBorder,
8350                                  const bool           toCreatePolygons,
8351                                  const bool           toCreatePolyedrs)
8352 {
8353   myLastCreatedElems.Clear();
8354   myLastCreatedNodes.Clear();
8355
8356   MESSAGE("::SewFreeBorder()");
8357   Sew_Error aResult = SEW_OK;
8358
8359   // ====================================
8360   //    find side nodes and elements
8361   // ====================================
8362
8363   list< const SMDS_MeshNode* > nSide[ 2 ];
8364   list< const SMDS_MeshElement* > eSide[ 2 ];
8365   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8366   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8367
8368   // Free border 1
8369   // --------------
8370   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8371                       nSide[0], eSide[0])) {
8372     MESSAGE(" Free Border 1 not found " );
8373     aResult = SEW_BORDER1_NOT_FOUND;
8374   }
8375   if (theSideIsFreeBorder) {
8376     // Free border 2
8377     // --------------
8378     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8379                         nSide[1], eSide[1])) {
8380       MESSAGE(" Free Border 2 not found " );
8381       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8382     }
8383   }
8384   if ( aResult != SEW_OK )
8385     return aResult;
8386
8387   if (!theSideIsFreeBorder) {
8388     // Side 2
8389     // --------------
8390
8391     // -------------------------------------------------------------------------
8392     // Algo:
8393     // 1. If nodes to merge are not coincident, move nodes of the free border
8394     //    from the coord sys defined by the direction from the first to last
8395     //    nodes of the border to the correspondent sys of the side 2
8396     // 2. On the side 2, find the links most co-directed with the correspondent
8397     //    links of the free border
8398     // -------------------------------------------------------------------------
8399
8400     // 1. Since sewing may break if there are volumes to split on the side 2,
8401     //    we wont move nodes but just compute new coordinates for them
8402     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8403     TNodeXYZMap nBordXYZ;
8404     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8405     list< const SMDS_MeshNode* >::iterator nBordIt;
8406
8407     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8408     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8409     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8410     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8411     double tol2 = 1.e-8;
8412     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8413     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8414       // Need node movement.
8415
8416       // find X and Z axes to create trsf
8417       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8418       gp_Vec X = Zs ^ Zb;
8419       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8420         // Zb || Zs
8421         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8422
8423       // coord systems
8424       gp_Ax3 toBordAx( Pb1, Zb, X );
8425       gp_Ax3 fromSideAx( Ps1, Zs, X );
8426       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8427       // set trsf
8428       gp_Trsf toBordSys, fromSide2Sys;
8429       toBordSys.SetTransformation( toBordAx );
8430       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8431       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8432
8433       // move
8434       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8435         const SMDS_MeshNode* n = *nBordIt;
8436         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8437         toBordSys.Transforms( xyz );
8438         fromSide2Sys.Transforms( xyz );
8439         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8440       }
8441     }
8442     else {
8443       // just insert nodes XYZ in the nBordXYZ map
8444       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8445         const SMDS_MeshNode* n = *nBordIt;
8446         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8447       }
8448     }
8449
8450     // 2. On the side 2, find the links most co-directed with the correspondent
8451     //    links of the free border
8452
8453     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8454     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8455     sideNodes.push_back( theSideFirstNode );
8456
8457     bool hasVolumes = false;
8458     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8459     set<long> foundSideLinkIDs, checkedLinkIDs;
8460     SMDS_VolumeTool volume;
8461     //const SMDS_MeshNode* faceNodes[ 4 ];
8462
8463     const SMDS_MeshNode*    sideNode;
8464     const SMDS_MeshElement* sideElem;
8465     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8466     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8467     nBordIt = bordNodes.begin();
8468     nBordIt++;
8469     // border node position and border link direction to compare with
8470     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8471     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8472     // choose next side node by link direction or by closeness to
8473     // the current border node:
8474     bool searchByDir = ( *nBordIt != theBordLastNode );
8475     do {
8476       // find the next node on the Side 2
8477       sideNode = 0;
8478       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8479       long linkID;
8480       checkedLinkIDs.clear();
8481       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8482
8483       // loop on inverse elements of current node (prevSideNode) on the Side 2
8484       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8485       while ( invElemIt->more() )
8486       {
8487         const SMDS_MeshElement* elem = invElemIt->next();
8488         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8489         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8490         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8491         bool isVolume = volume.Set( elem );
8492         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8493         if ( isVolume ) // --volume
8494           hasVolumes = true;
8495         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8496           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8497           if(elem->IsQuadratic()) {
8498             const SMDS_VtkFace* F =
8499               dynamic_cast<const SMDS_VtkFace*>(elem);
8500             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8501             // use special nodes iterator
8502             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8503             while( anIter->more() ) {
8504               nodes[ iNode ] = cast2Node(anIter->next());
8505               if ( nodes[ iNode++ ] == prevSideNode )
8506                 iPrevNode = iNode - 1;
8507             }
8508           }
8509           else {
8510             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8511             while ( nIt->more() ) {
8512               nodes[ iNode ] = cast2Node( nIt->next() );
8513               if ( nodes[ iNode++ ] == prevSideNode )
8514                 iPrevNode = iNode - 1;
8515             }
8516           }
8517           // there are 2 links to check
8518           nbNodes = 2;
8519         }
8520         else // --edge
8521           continue;
8522         // loop on links, to be precise, on the second node of links
8523         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8524           const SMDS_MeshNode* n = nodes[ iNode ];
8525           if ( isVolume ) {
8526             if ( !volume.IsLinked( n, prevSideNode ))
8527               continue;
8528           }
8529           else {
8530             if ( iNode ) // a node before prevSideNode
8531               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8532             else         // a node after prevSideNode
8533               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8534           }
8535           // check if this link was already used
8536           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8537           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8538           if (!isJustChecked &&
8539               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8540           {
8541             // test a link geometrically
8542             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8543             bool linkIsBetter = false;
8544             double dot = 0.0, dist = 0.0;
8545             if ( searchByDir ) { // choose most co-directed link
8546               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8547               linkIsBetter = ( dot > maxDot );
8548             }
8549             else { // choose link with the node closest to bordPos
8550               dist = ( nextXYZ - bordPos ).SquareModulus();
8551               linkIsBetter = ( dist < minDist );
8552             }
8553             if ( linkIsBetter ) {
8554               maxDot = dot;
8555               minDist = dist;
8556               linkID = iLink;
8557               sideNode = n;
8558               sideElem = elem;
8559             }
8560           }
8561         }
8562       } // loop on inverse elements of prevSideNode
8563
8564       if ( !sideNode ) {
8565         MESSAGE(" Cant find path by links of the Side 2 ");
8566         return SEW_BAD_SIDE_NODES;
8567       }
8568       sideNodes.push_back( sideNode );
8569       sideElems.push_back( sideElem );
8570       foundSideLinkIDs.insert ( linkID );
8571       prevSideNode = sideNode;
8572
8573       if ( *nBordIt == theBordLastNode )
8574         searchByDir = false;
8575       else {
8576         // find the next border link to compare with
8577         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8578         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8579         // move to next border node if sideNode is before forward border node (bordPos)
8580         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8581           prevBordNode = *nBordIt;
8582           nBordIt++;
8583           bordPos = nBordXYZ[ *nBordIt ];
8584           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8585           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8586         }
8587       }
8588     }
8589     while ( sideNode != theSideSecondNode );
8590
8591     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8592       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8593       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8594     }
8595   } // end nodes search on the side 2
8596
8597   // ============================
8598   // sew the border to the side 2
8599   // ============================
8600
8601   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8602   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8603
8604   TListOfListOfNodes nodeGroupsToMerge;
8605   if ( nbNodes[0] == nbNodes[1] ||
8606        ( theSideIsFreeBorder && !theSideThirdNode)) {
8607
8608     // all nodes are to be merged
8609
8610     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8611          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8612          nIt[0]++, nIt[1]++ )
8613     {
8614       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8615       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8616       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8617     }
8618   }
8619   else {
8620
8621     // insert new nodes into the border and the side to get equal nb of segments
8622
8623     // get normalized parameters of nodes on the borders
8624     //double param[ 2 ][ maxNbNodes ];
8625     double* param[ 2 ];
8626     param[0] = new double [ maxNbNodes ];
8627     param[1] = new double [ maxNbNodes ];
8628     int iNode, iBord;
8629     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8630       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8631       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8632       const SMDS_MeshNode* nPrev = *nIt;
8633       double bordLength = 0;
8634       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8635         const SMDS_MeshNode* nCur = *nIt;
8636         gp_XYZ segment (nCur->X() - nPrev->X(),
8637                         nCur->Y() - nPrev->Y(),
8638                         nCur->Z() - nPrev->Z());
8639         double segmentLen = segment.Modulus();
8640         bordLength += segmentLen;
8641         param[ iBord ][ iNode ] = bordLength;
8642         nPrev = nCur;
8643       }
8644       // normalize within [0,1]
8645       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8646         param[ iBord ][ iNode ] /= bordLength;
8647       }
8648     }
8649
8650     // loop on border segments
8651     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8652     int i[ 2 ] = { 0, 0 };
8653     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8654     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8655
8656     TElemOfNodeListMap insertMap;
8657     TElemOfNodeListMap::iterator insertMapIt;
8658     // insertMap is
8659     // key:   elem to insert nodes into
8660     // value: 2 nodes to insert between + nodes to be inserted
8661     do {
8662       bool next[ 2 ] = { false, false };
8663
8664       // find min adjacent segment length after sewing
8665       double nextParam = 10., prevParam = 0;
8666       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8667         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8668           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8669         if ( i[ iBord ] > 0 )
8670           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8671       }
8672       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8673       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8674       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8675
8676       // choose to insert or to merge nodes
8677       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8678       if ( Abs( du ) <= minSegLen * 0.2 ) {
8679         // merge
8680         // ------
8681         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8682         const SMDS_MeshNode* n0 = *nIt[0];
8683         const SMDS_MeshNode* n1 = *nIt[1];
8684         nodeGroupsToMerge.back().push_back( n1 );
8685         nodeGroupsToMerge.back().push_back( n0 );
8686         // position of node of the border changes due to merge
8687         param[ 0 ][ i[0] ] += du;
8688         // move n1 for the sake of elem shape evaluation during insertion.
8689         // n1 will be removed by MergeNodes() anyway
8690         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8691         next[0] = next[1] = true;
8692       }
8693       else {
8694         // insert
8695         // ------
8696         int intoBord = ( du < 0 ) ? 0 : 1;
8697         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8698         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8699         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8700         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8701         if ( intoBord == 1 ) {
8702           // move node of the border to be on a link of elem of the side
8703           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8704           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8705           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8706           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8707           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8708         }
8709         insertMapIt = insertMap.find( elem );
8710         bool notFound = ( insertMapIt == insertMap.end() );
8711         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8712         if ( otherLink ) {
8713           // insert into another link of the same element:
8714           // 1. perform insertion into the other link of the elem
8715           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8716           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8717           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8718           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8719           // 2. perform insertion into the link of adjacent faces
8720           while (true) {
8721             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8722             if ( adjElem )
8723               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8724             else
8725               break;
8726           }
8727           if (toCreatePolyedrs) {
8728             // perform insertion into the links of adjacent volumes
8729             UpdateVolumes(n12, n22, nodeList);
8730           }
8731           // 3. find an element appeared on n1 and n2 after the insertion
8732           insertMap.erase( elem );
8733           elem = findAdjacentFace( n1, n2, 0 );
8734         }
8735         if ( notFound || otherLink ) {
8736           // add element and nodes of the side into the insertMap
8737           insertMapIt = insertMap.insert
8738             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8739           (*insertMapIt).second.push_back( n1 );
8740           (*insertMapIt).second.push_back( n2 );
8741         }
8742         // add node to be inserted into elem
8743         (*insertMapIt).second.push_back( nIns );
8744         next[ 1 - intoBord ] = true;
8745       }
8746
8747       // go to the next segment
8748       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8749         if ( next[ iBord ] ) {
8750           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8751             eIt[ iBord ]++;
8752           nPrev[ iBord ] = *nIt[ iBord ];
8753           nIt[ iBord ]++; i[ iBord ]++;
8754         }
8755       }
8756     }
8757     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8758
8759     // perform insertion of nodes into elements
8760
8761     for (insertMapIt = insertMap.begin();
8762          insertMapIt != insertMap.end();
8763          insertMapIt++ )
8764     {
8765       const SMDS_MeshElement* elem = (*insertMapIt).first;
8766       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8767       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8768       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8769
8770       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8771
8772       if ( !theSideIsFreeBorder ) {
8773         // look for and insert nodes into the faces adjacent to elem
8774         while (true) {
8775           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8776           if ( adjElem )
8777             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8778           else
8779             break;
8780         }
8781       }
8782       if (toCreatePolyedrs) {
8783         // perform insertion into the links of adjacent volumes
8784         UpdateVolumes(n1, n2, nodeList);
8785       }
8786     }
8787
8788     delete param[0];
8789     delete param[1];
8790   } // end: insert new nodes
8791
8792   MergeNodes ( nodeGroupsToMerge );
8793
8794   return aResult;
8795 }
8796
8797 //=======================================================================
8798 //function : InsertNodesIntoLink
8799 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8800 //           and theBetweenNode2 and split theElement
8801 //=======================================================================
8802
8803 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8804                                            const SMDS_MeshNode*        theBetweenNode1,
8805                                            const SMDS_MeshNode*        theBetweenNode2,
8806                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8807                                            const bool                  toCreatePoly)
8808 {
8809   if ( theFace->GetType() != SMDSAbs_Face ) return;
8810
8811   // find indices of 2 link nodes and of the rest nodes
8812   int iNode = 0, il1, il2, i3, i4;
8813   il1 = il2 = i3 = i4 = -1;
8814   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8815   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8816
8817   if(theFace->IsQuadratic()) {
8818     const SMDS_VtkFace* F =
8819       dynamic_cast<const SMDS_VtkFace*>(theFace);
8820     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8821     // use special nodes iterator
8822     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8823     while( anIter->more() ) {
8824       const SMDS_MeshNode* n = cast2Node(anIter->next());
8825       if ( n == theBetweenNode1 )
8826         il1 = iNode;
8827       else if ( n == theBetweenNode2 )
8828         il2 = iNode;
8829       else if ( i3 < 0 )
8830         i3 = iNode;
8831       else
8832         i4 = iNode;
8833       nodes[ iNode++ ] = n;
8834     }
8835   }
8836   else {
8837     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8838     while ( nodeIt->more() ) {
8839       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8840       if ( n == theBetweenNode1 )
8841         il1 = iNode;
8842       else if ( n == theBetweenNode2 )
8843         il2 = iNode;
8844       else if ( i3 < 0 )
8845         i3 = iNode;
8846       else
8847         i4 = iNode;
8848       nodes[ iNode++ ] = n;
8849     }
8850   }
8851   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8852     return ;
8853
8854   // arrange link nodes to go one after another regarding the face orientation
8855   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8856   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8857   if ( reverse ) {
8858     iNode = il1;
8859     il1 = il2;
8860     il2 = iNode;
8861     aNodesToInsert.reverse();
8862   }
8863   // check that not link nodes of a quadrangles are in good order
8864   int nbFaceNodes = theFace->NbNodes();
8865   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8866     iNode = i3;
8867     i3 = i4;
8868     i4 = iNode;
8869   }
8870
8871   if (toCreatePoly || theFace->IsPoly()) {
8872
8873     iNode = 0;
8874     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8875
8876     // add nodes of face up to first node of link
8877     bool isFLN = false;
8878
8879     if(theFace->IsQuadratic()) {
8880       const SMDS_VtkFace* F =
8881         dynamic_cast<const SMDS_VtkFace*>(theFace);
8882       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8883       // use special nodes iterator
8884       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8885       while( anIter->more()  && !isFLN ) {
8886         const SMDS_MeshNode* n = cast2Node(anIter->next());
8887         poly_nodes[iNode++] = n;
8888         if (n == nodes[il1]) {
8889           isFLN = true;
8890         }
8891       }
8892       // add nodes to insert
8893       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8894       for (; nIt != aNodesToInsert.end(); nIt++) {
8895         poly_nodes[iNode++] = *nIt;
8896       }
8897       // add nodes of face starting from last node of link
8898       while ( anIter->more() ) {
8899         poly_nodes[iNode++] = cast2Node(anIter->next());
8900       }
8901     }
8902     else {
8903       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8904       while ( nodeIt->more() && !isFLN ) {
8905         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8906         poly_nodes[iNode++] = n;
8907         if (n == nodes[il1]) {
8908           isFLN = true;
8909         }
8910       }
8911       // add nodes to insert
8912       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8913       for (; nIt != aNodesToInsert.end(); nIt++) {
8914         poly_nodes[iNode++] = *nIt;
8915       }
8916       // add nodes of face starting from last node of link
8917       while ( nodeIt->more() ) {
8918         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8919         poly_nodes[iNode++] = n;
8920       }
8921     }
8922
8923     // edit or replace the face
8924     SMESHDS_Mesh *aMesh = GetMeshDS();
8925
8926     if (theFace->IsPoly()) {
8927       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8928     }
8929     else {
8930       int aShapeId = FindShape( theFace );
8931
8932       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8933       myLastCreatedElems.Append(newElem);
8934       if ( aShapeId && newElem )
8935         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8936
8937       aMesh->RemoveElement(theFace);
8938     }
8939     return;
8940   }
8941
8942   SMESHDS_Mesh *aMesh = GetMeshDS();
8943   if( !theFace->IsQuadratic() ) {
8944
8945     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8946     int nbLinkNodes = 2 + aNodesToInsert.size();
8947     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8948     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8949     linkNodes[ 0 ] = nodes[ il1 ];
8950     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8951     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8952     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8953       linkNodes[ iNode++ ] = *nIt;
8954     }
8955     // decide how to split a quadrangle: compare possible variants
8956     // and choose which of splits to be a quadrangle
8957     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8958     if ( nbFaceNodes == 3 ) {
8959       iBestQuad = nbSplits;
8960       i4 = i3;
8961     }
8962     else if ( nbFaceNodes == 4 ) {
8963       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8964       double aBestRate = DBL_MAX;
8965       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8966         i1 = 0; i2 = 1;
8967         double aBadRate = 0;
8968         // evaluate elements quality
8969         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8970           if ( iSplit == iQuad ) {
8971             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8972                                    linkNodes[ i2++ ],
8973                                    nodes[ i3 ],
8974                                    nodes[ i4 ]);
8975             aBadRate += getBadRate( &quad, aCrit );
8976           }
8977           else {
8978             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8979                                    linkNodes[ i2++ ],
8980                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8981             aBadRate += getBadRate( &tria, aCrit );
8982           }
8983         }
8984         // choice
8985         if ( aBadRate < aBestRate ) {
8986           iBestQuad = iQuad;
8987           aBestRate = aBadRate;
8988         }
8989       }
8990     }
8991
8992     // create new elements
8993     int aShapeId = FindShape( theFace );
8994
8995     i1 = 0; i2 = 1;
8996     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8997       SMDS_MeshElement* newElem = 0;
8998       if ( iSplit == iBestQuad )
8999         newElem = aMesh->AddFace (linkNodes[ i1++ ],
9000                                   linkNodes[ i2++ ],
9001                                   nodes[ i3 ],
9002                                   nodes[ i4 ]);
9003       else
9004         newElem = aMesh->AddFace (linkNodes[ i1++ ],
9005                                   linkNodes[ i2++ ],
9006                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
9007       myLastCreatedElems.Append(newElem);
9008       if ( aShapeId && newElem )
9009         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9010     }
9011
9012     // change nodes of theFace
9013     const SMDS_MeshNode* newNodes[ 4 ];
9014     newNodes[ 0 ] = linkNodes[ i1 ];
9015     newNodes[ 1 ] = linkNodes[ i2 ];
9016     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
9017     newNodes[ 3 ] = nodes[ i4 ];
9018     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
9019     const SMDS_MeshElement* newElem = 0;
9020     if (iSplit == iBestQuad)
9021       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
9022     else
9023       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
9024     myLastCreatedElems.Append(newElem);
9025     if ( aShapeId && newElem )
9026       aMesh->SetMeshElementOnShape( newElem, aShapeId );
9027 } // end if(!theFace->IsQuadratic())
9028   else { // theFace is quadratic
9029     // we have to split theFace on simple triangles and one simple quadrangle
9030     int tmp = il1/2;
9031     int nbshift = tmp*2;
9032     // shift nodes in nodes[] by nbshift
9033     int i,j;
9034     for(i=0; i<nbshift; i++) {
9035       const SMDS_MeshNode* n = nodes[0];
9036       for(j=0; j<nbFaceNodes-1; j++) {
9037         nodes[j] = nodes[j+1];
9038       }
9039       nodes[nbFaceNodes-1] = n;
9040     }
9041     il1 = il1 - nbshift;
9042     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9043     //   n0      n1     n2    n0      n1     n2
9044     //     +-----+-----+        +-----+-----+
9045     //      \         /         |           |
9046     //       \       /          |           |
9047     //      n5+     +n3       n7+           +n3
9048     //         \   /            |           |
9049     //          \ /             |           |
9050     //           +              +-----+-----+
9051     //           n4           n6      n5     n4
9052
9053     // create new elements
9054     int aShapeId = FindShape( theFace );
9055
9056     int n1,n2,n3;
9057     if(nbFaceNodes==6) { // quadratic triangle
9058       SMDS_MeshElement* newElem =
9059         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9060       myLastCreatedElems.Append(newElem);
9061       if ( aShapeId && newElem )
9062         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9063       if(theFace->IsMediumNode(nodes[il1])) {
9064         // create quadrangle
9065         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9066         myLastCreatedElems.Append(newElem);
9067         if ( aShapeId && newElem )
9068           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9069         n1 = 1;
9070         n2 = 2;
9071         n3 = 3;
9072       }
9073       else {
9074         // create quadrangle
9075         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9076         myLastCreatedElems.Append(newElem);
9077         if ( aShapeId && newElem )
9078           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9079         n1 = 0;
9080         n2 = 1;
9081         n3 = 5;
9082       }
9083     }
9084     else { // nbFaceNodes==8 - quadratic quadrangle
9085       SMDS_MeshElement* newElem =
9086         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9087       myLastCreatedElems.Append(newElem);
9088       if ( aShapeId && newElem )
9089         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9090       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9091       myLastCreatedElems.Append(newElem);
9092       if ( aShapeId && newElem )
9093         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9094       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9095       myLastCreatedElems.Append(newElem);
9096       if ( aShapeId && newElem )
9097         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9098       if(theFace->IsMediumNode(nodes[il1])) {
9099         // create quadrangle
9100         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9101         myLastCreatedElems.Append(newElem);
9102         if ( aShapeId && newElem )
9103           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9104         n1 = 1;
9105         n2 = 2;
9106         n3 = 3;
9107       }
9108       else {
9109         // create quadrangle
9110         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9111         myLastCreatedElems.Append(newElem);
9112         if ( aShapeId && newElem )
9113           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9114         n1 = 0;
9115         n2 = 1;
9116         n3 = 7;
9117       }
9118     }
9119     // create needed triangles using n1,n2,n3 and inserted nodes
9120     int nbn = 2 + aNodesToInsert.size();
9121     //const SMDS_MeshNode* aNodes[nbn];
9122     vector<const SMDS_MeshNode*> aNodes(nbn);
9123     aNodes[0] = nodes[n1];
9124     aNodes[nbn-1] = nodes[n2];
9125     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9126     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9127       aNodes[iNode++] = *nIt;
9128     }
9129     for(i=1; i<nbn; i++) {
9130       SMDS_MeshElement* newElem =
9131         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9132       myLastCreatedElems.Append(newElem);
9133       if ( aShapeId && newElem )
9134         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9135     }
9136   }
9137   // remove old face
9138   aMesh->RemoveElement(theFace);
9139 }
9140
9141 //=======================================================================
9142 //function : UpdateVolumes
9143 //purpose  :
9144 //=======================================================================
9145 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9146                                       const SMDS_MeshNode*        theBetweenNode2,
9147                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9148 {
9149   myLastCreatedElems.Clear();
9150   myLastCreatedNodes.Clear();
9151
9152   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9153   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9154     const SMDS_MeshElement* elem = invElemIt->next();
9155
9156     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9157     SMDS_VolumeTool aVolume (elem);
9158     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9159       continue;
9160
9161     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9162     int iface, nbFaces = aVolume.NbFaces();
9163     vector<const SMDS_MeshNode *> poly_nodes;
9164     vector<int> quantities (nbFaces);
9165
9166     for (iface = 0; iface < nbFaces; iface++) {
9167       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9168       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9169       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9170
9171       for (int inode = 0; inode < nbFaceNodes; inode++) {
9172         poly_nodes.push_back(faceNodes[inode]);
9173
9174         if (nbInserted == 0) {
9175           if (faceNodes[inode] == theBetweenNode1) {
9176             if (faceNodes[inode + 1] == theBetweenNode2) {
9177               nbInserted = theNodesToInsert.size();
9178
9179               // add nodes to insert
9180               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9181               for (; nIt != theNodesToInsert.end(); nIt++) {
9182                 poly_nodes.push_back(*nIt);
9183               }
9184             }
9185           }
9186           else if (faceNodes[inode] == theBetweenNode2) {
9187             if (faceNodes[inode + 1] == theBetweenNode1) {
9188               nbInserted = theNodesToInsert.size();
9189
9190               // add nodes to insert in reversed order
9191               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9192               nIt--;
9193               for (; nIt != theNodesToInsert.begin(); nIt--) {
9194                 poly_nodes.push_back(*nIt);
9195               }
9196               poly_nodes.push_back(*nIt);
9197             }
9198           }
9199           else {
9200           }
9201         }
9202       }
9203       quantities[iface] = nbFaceNodes + nbInserted;
9204     }
9205
9206     // Replace or update the volume
9207     SMESHDS_Mesh *aMesh = GetMeshDS();
9208
9209     if (elem->IsPoly()) {
9210       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9211
9212     }
9213     else {
9214       int aShapeId = FindShape( elem );
9215
9216       SMDS_MeshElement* newElem =
9217         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9218       myLastCreatedElems.Append(newElem);
9219       if (aShapeId && newElem)
9220         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9221
9222       aMesh->RemoveElement(elem);
9223     }
9224   }
9225 }
9226
9227 //=======================================================================
9228 /*!
9229  * \brief Convert elements contained in a submesh to quadratic
9230  * \return int - nb of checked elements
9231  */
9232 //=======================================================================
9233
9234 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9235                                              SMESH_MesherHelper& theHelper,
9236                                              const bool          theForce3d)
9237 {
9238   int nbElem = 0;
9239   if( !theSm ) return nbElem;
9240
9241   vector<int> nbNodeInFaces;
9242   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9243   while(ElemItr->more())
9244   {
9245     nbElem++;
9246     const SMDS_MeshElement* elem = ElemItr->next();
9247     if( !elem || elem->IsQuadratic() ) continue;
9248
9249     int id = elem->GetID();
9250     int nbNodes = elem->NbNodes();
9251     SMDSAbs_ElementType aType = elem->GetType();
9252
9253     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9254     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9255       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9256
9257     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9258
9259     const SMDS_MeshElement* NewElem = 0;
9260
9261     switch( aType )
9262     {
9263     case SMDSAbs_Edge :
9264       {
9265         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9266         break;
9267       }
9268     case SMDSAbs_Face :
9269       {
9270         switch(nbNodes)
9271         {
9272         case 3:
9273           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9274           break;
9275         case 4:
9276           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9277           break;
9278         default:
9279           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9280           continue;
9281         }
9282         break;
9283       }
9284     case SMDSAbs_Volume :
9285       {
9286         switch(nbNodes)
9287         {
9288         case 4:
9289           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9290           break;
9291         case 5:
9292           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9293           break;
9294         case 6:
9295           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9296           break;
9297         case 8:
9298           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9299                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9300           break;
9301         default:
9302           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9303         }
9304         break;
9305       }
9306     default :
9307       continue;
9308     }
9309     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9310     if( NewElem )
9311       theSm->AddElement( NewElem );
9312   }
9313 //  if (!GetMeshDS()->isCompacted())
9314 //    GetMeshDS()->compactMesh();
9315   return nbElem;
9316 }
9317
9318 //=======================================================================
9319 //function : ConvertToQuadratic
9320 //purpose  :
9321 //=======================================================================
9322 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9323 {
9324   SMESHDS_Mesh* meshDS = GetMeshDS();
9325
9326   SMESH_MesherHelper aHelper(*myMesh);
9327   aHelper.SetIsQuadratic( true );
9328
9329   int nbCheckedElems = 0;
9330   if ( myMesh->HasShapeToMesh() )
9331   {
9332     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9333     {
9334       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9335       while ( smIt->more() ) {
9336         SMESH_subMesh* sm = smIt->next();
9337         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9338           aHelper.SetSubShape( sm->GetSubShape() );
9339           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9340         }
9341       }
9342     }
9343   }
9344   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9345   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9346   {
9347     SMESHDS_SubMesh *smDS = 0;
9348     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9349     while(aEdgeItr->more())
9350     {
9351       const SMDS_MeshEdge* edge = aEdgeItr->next();
9352       if(edge && !edge->IsQuadratic())
9353       {
9354         int id = edge->GetID();
9355         //MESSAGE("edge->GetID() " << id);
9356         const SMDS_MeshNode* n1 = edge->GetNode(0);
9357         const SMDS_MeshNode* n2 = edge->GetNode(1);
9358
9359         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9360
9361         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9362         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9363       }
9364     }
9365     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9366     while(aFaceItr->more())
9367     {
9368       const SMDS_MeshFace* face = aFaceItr->next();
9369       if(!face || face->IsQuadratic() ) continue;
9370
9371       int id = face->GetID();
9372       int nbNodes = face->NbNodes();
9373       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9374
9375       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9376
9377       SMDS_MeshFace * NewFace = 0;
9378       switch(nbNodes)
9379       {
9380       case 3:
9381         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9382         break;
9383       case 4:
9384         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9385         break;
9386       default:
9387         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9388       }
9389       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9390     }
9391     vector<int> nbNodeInFaces;
9392     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9393     while(aVolumeItr->more())
9394     {
9395       const SMDS_MeshVolume* volume = aVolumeItr->next();
9396       if(!volume || volume->IsQuadratic() ) continue;
9397
9398       int id = volume->GetID();
9399       int nbNodes = volume->NbNodes();
9400       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9401       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9402         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9403
9404       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9405
9406       SMDS_MeshVolume * NewVolume = 0;
9407       switch(nbNodes)
9408       {
9409       case 4:
9410         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9411                                       nodes[3], id, theForce3d );
9412         break;
9413       case 5:
9414         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9415                                       nodes[3], nodes[4], id, theForce3d);
9416         break;
9417       case 6:
9418         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9419                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9420         break;
9421       case 8:
9422         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9423                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9424         break;
9425       default:
9426         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9427       }
9428       ReplaceElemInGroups(volume, NewVolume, meshDS);
9429     }
9430   }
9431
9432   if ( !theForce3d )
9433   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9434     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9435     aHelper.FixQuadraticElements();
9436   }
9437 }
9438
9439 //================================================================================
9440 /*!
9441  * \brief Makes given elements quadratic
9442  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9443  *  \param theElements - elements to make quadratic 
9444  */
9445 //================================================================================
9446
9447 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9448                                           TIDSortedElemSet& theElements)
9449 {
9450   if ( theElements.empty() ) return;
9451
9452   // we believe that all theElements are of the same type
9453   SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9454   
9455   // get all nodes shared by theElements
9456   TIDSortedNodeSet allNodes;
9457   TIDSortedElemSet::iterator eIt = theElements.begin();
9458   for ( ; eIt != theElements.end(); ++eIt )
9459     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9460
9461   // complete theElements with elements of lower dim whose all nodes are in allNodes
9462
9463   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9464   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9465   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9466   for ( ; nIt != allNodes.end(); ++nIt )
9467   {
9468     const SMDS_MeshNode* n = *nIt;
9469     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9470     while ( invIt->more() )
9471     {
9472       const SMDS_MeshElement* e = invIt->next();
9473       if ( e->IsQuadratic() )
9474       {
9475         quadAdjacentElems[ e->GetType() ].insert( e );
9476         continue;
9477       }
9478       if ( e->GetType() >= elemType )
9479       {
9480         continue; // same type of more complex linear element
9481       }
9482
9483       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9484         continue; // e is already checked
9485
9486       // check nodes
9487       bool allIn = true;
9488       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9489       while ( nodeIt->more() && allIn )
9490         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9491       if ( allIn )
9492         theElements.insert(e );
9493     }
9494   }
9495
9496   SMESH_MesherHelper helper(*myMesh);
9497   helper.SetIsQuadratic( true );
9498
9499   // add links of quadratic adjacent elements to the helper
9500
9501   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9502     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9503           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9504     {
9505       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9506     }
9507   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9508     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9509           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9510     {
9511       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9512     }
9513   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9514     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9515           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9516     {
9517       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9518     }
9519
9520   // make quadratic elements instead of linear ones
9521
9522   SMESHDS_Mesh* meshDS = GetMeshDS();
9523   SMESHDS_SubMesh* smDS = 0;
9524   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9525   {
9526     const SMDS_MeshElement* elem = *eIt;
9527     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9528       continue;
9529
9530     int id = elem->GetID();
9531     SMDSAbs_ElementType type = elem->GetType();
9532     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9533
9534     if ( !smDS || !smDS->Contains( elem ))
9535       smDS = meshDS->MeshElements( elem->getshapeId() );
9536     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9537
9538     SMDS_MeshElement * newElem = 0;
9539     switch( nodes.size() )
9540     {
9541     case 4: // cases for most multiple element types go first (for optimization)
9542       if ( type == SMDSAbs_Volume )
9543         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9544       else
9545         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9546       break;
9547     case 8:
9548       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9549                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9550       break;
9551     case 3:
9552       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9553       break;
9554     case 2:
9555       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9556       break;
9557     case 5:
9558       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9559                                  nodes[4], id, theForce3d);
9560       break;
9561     case 6:
9562       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9563                                  nodes[4], nodes[5], id, theForce3d);
9564       break;
9565     default:;
9566     }
9567     ReplaceElemInGroups( elem, newElem, meshDS);
9568     if( newElem && smDS )
9569       smDS->AddElement( newElem );
9570   }
9571
9572   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9573   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9574     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9575     helper.FixQuadraticElements();
9576   }
9577 }
9578
9579 //=======================================================================
9580 /*!
9581  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9582  * \return int - nb of checked elements
9583  */
9584 //=======================================================================
9585
9586 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9587                                      SMDS_ElemIteratorPtr theItr,
9588                                      const int            theShapeID)
9589 {
9590   int nbElem = 0;
9591   SMESHDS_Mesh* meshDS = GetMeshDS();
9592
9593   while( theItr->more() )
9594   {
9595     const SMDS_MeshElement* elem = theItr->next();
9596     nbElem++;
9597     if( elem && elem->IsQuadratic())
9598     {
9599       int id                    = elem->GetID();
9600       int nbCornerNodes         = elem->NbCornerNodes();
9601       SMDSAbs_ElementType aType = elem->GetType();
9602
9603       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9604
9605       //remove a quadratic element
9606       if ( !theSm || !theSm->Contains( elem ))
9607         theSm = meshDS->MeshElements( elem->getshapeId() );
9608       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9609
9610       // remove medium nodes
9611       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9612         if ( nodes[i]->NbInverseElements() == 0 )
9613           meshDS->RemoveFreeNode( nodes[i], theSm );
9614
9615       // add a linear element
9616       nodes.resize( nbCornerNodes );
9617       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9618       ReplaceElemInGroups(elem, newElem, meshDS);
9619       if( theSm && newElem )
9620         theSm->AddElement( newElem );
9621     }
9622   }
9623   return nbElem;
9624 }
9625
9626 //=======================================================================
9627 //function : ConvertFromQuadratic
9628 //purpose  :
9629 //=======================================================================
9630
9631 bool SMESH_MeshEditor::ConvertFromQuadratic()
9632 {
9633   int nbCheckedElems = 0;
9634   if ( myMesh->HasShapeToMesh() )
9635   {
9636     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9637     {
9638       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9639       while ( smIt->more() ) {
9640         SMESH_subMesh* sm = smIt->next();
9641         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9642           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9643       }
9644     }
9645   }
9646
9647   int totalNbElems =
9648     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9649   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9650   {
9651     SMESHDS_SubMesh *aSM = 0;
9652     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9653   }
9654
9655   return true;
9656 }
9657
9658 namespace
9659 {
9660   //================================================================================
9661   /*!
9662    * \brief Return true if all medium nodes of the element are in the node set
9663    */
9664   //================================================================================
9665
9666   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9667   {
9668     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9669       if ( !nodeSet.count( elem->GetNode(i) ))
9670         return false;
9671     return true;
9672   }
9673 }
9674
9675 //================================================================================
9676 /*!
9677  * \brief Makes given elements linear
9678  */
9679 //================================================================================
9680
9681 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9682 {
9683   if ( theElements.empty() ) return;
9684
9685   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9686   set<int> mediumNodeIDs;
9687   TIDSortedElemSet::iterator eIt = theElements.begin();
9688   for ( ; eIt != theElements.end(); ++eIt )
9689   {
9690     const SMDS_MeshElement* e = *eIt;
9691     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9692       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9693   }
9694
9695   // replace given elements by linear ones
9696   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9697   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9698   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9699
9700   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9701   // except those elements sharing medium nodes of quadratic element whose medium nodes
9702   // are not all in mediumNodeIDs
9703
9704   // get remaining medium nodes
9705   TIDSortedNodeSet mediumNodes;
9706   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9707   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9708     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9709       mediumNodes.insert( mediumNodes.end(), n );
9710
9711   // find more quadratic elements to convert
9712   TIDSortedElemSet moreElemsToConvert;
9713   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9714   for ( ; nIt != mediumNodes.end(); ++nIt )
9715   {
9716     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9717     while ( invIt->more() )
9718     {
9719       const SMDS_MeshElement* e = invIt->next();
9720       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9721       {
9722         // find a more complex element including e and
9723         // whose medium nodes are not in mediumNodes
9724         bool complexFound = false;
9725         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9726         {
9727           SMDS_ElemIteratorPtr invIt2 =
9728             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9729           while ( invIt2->more() )
9730           {
9731             const SMDS_MeshElement* eComplex = invIt2->next();
9732             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9733             {
9734               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9735               if ( nbCommonNodes == e->NbNodes())
9736               {
9737                 complexFound = true;
9738                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9739                 break;
9740               }
9741             }
9742           }
9743         }
9744         if ( !complexFound )
9745           moreElemsToConvert.insert( e );
9746       }
9747     }
9748   }
9749   elemIt = SMDS_ElemIteratorPtr
9750     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9751   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9752 }
9753
9754 //=======================================================================
9755 //function : SewSideElements
9756 //purpose  :
9757 //=======================================================================
9758
9759 SMESH_MeshEditor::Sew_Error
9760 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9761                                    TIDSortedElemSet&    theSide2,
9762                                    const SMDS_MeshNode* theFirstNode1,
9763                                    const SMDS_MeshNode* theFirstNode2,
9764                                    const SMDS_MeshNode* theSecondNode1,
9765                                    const SMDS_MeshNode* theSecondNode2)
9766 {
9767   myLastCreatedElems.Clear();
9768   myLastCreatedNodes.Clear();
9769
9770   MESSAGE ("::::SewSideElements()");
9771   if ( theSide1.size() != theSide2.size() )
9772     return SEW_DIFF_NB_OF_ELEMENTS;
9773
9774   Sew_Error aResult = SEW_OK;
9775   // Algo:
9776   // 1. Build set of faces representing each side
9777   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9778   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9779
9780   // =======================================================================
9781   // 1. Build set of faces representing each side:
9782   // =======================================================================
9783   // a. build set of nodes belonging to faces
9784   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9785   // c. create temporary faces representing side of volumes if correspondent
9786   //    face does not exist
9787
9788   SMESHDS_Mesh* aMesh = GetMeshDS();
9789   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9790   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9791   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9792   set<const SMDS_MeshElement*> volSet1,  volSet2;
9793   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9794   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9795   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9796   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9797   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9798   int iSide, iFace, iNode;
9799
9800   list<const SMDS_MeshElement* > tempFaceList;
9801   for ( iSide = 0; iSide < 2; iSide++ ) {
9802     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9803     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9804     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9805     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9806     set<const SMDS_MeshElement*>::iterator vIt;
9807     TIDSortedElemSet::iterator eIt;
9808     set<const SMDS_MeshNode*>::iterator    nIt;
9809
9810     // check that given nodes belong to given elements
9811     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9812     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9813     int firstIndex = -1, secondIndex = -1;
9814     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9815       const SMDS_MeshElement* elem = *eIt;
9816       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9817       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9818       if ( firstIndex > -1 && secondIndex > -1 ) break;
9819     }
9820     if ( firstIndex < 0 || secondIndex < 0 ) {
9821       // we can simply return until temporary faces created
9822       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9823     }
9824
9825     // -----------------------------------------------------------
9826     // 1a. Collect nodes of existing faces
9827     //     and build set of face nodes in order to detect missing
9828     //     faces corresponding to sides of volumes
9829     // -----------------------------------------------------------
9830
9831     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9832
9833     // loop on the given element of a side
9834     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9835       //const SMDS_MeshElement* elem = *eIt;
9836       const SMDS_MeshElement* elem = *eIt;
9837       if ( elem->GetType() == SMDSAbs_Face ) {
9838         faceSet->insert( elem );
9839         set <const SMDS_MeshNode*> faceNodeSet;
9840         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9841         while ( nodeIt->more() ) {
9842           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9843           nodeSet->insert( n );
9844           faceNodeSet.insert( n );
9845         }
9846         setOfFaceNodeSet.insert( faceNodeSet );
9847       }
9848       else if ( elem->GetType() == SMDSAbs_Volume )
9849         volSet->insert( elem );
9850     }
9851     // ------------------------------------------------------------------------------
9852     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9853     // ------------------------------------------------------------------------------
9854
9855     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9856       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9857       while ( fIt->more() ) { // loop on faces sharing a node
9858         const SMDS_MeshElement* f = fIt->next();
9859         if ( faceSet->find( f ) == faceSet->end() ) {
9860           // check if all nodes are in nodeSet and
9861           // complete setOfFaceNodeSet if they are
9862           set <const SMDS_MeshNode*> faceNodeSet;
9863           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9864           bool allInSet = true;
9865           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9866             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9867             if ( nodeSet->find( n ) == nodeSet->end() )
9868               allInSet = false;
9869             else
9870               faceNodeSet.insert( n );
9871           }
9872           if ( allInSet ) {
9873             faceSet->insert( f );
9874             setOfFaceNodeSet.insert( faceNodeSet );
9875           }
9876         }
9877       }
9878     }
9879
9880     // -------------------------------------------------------------------------
9881     // 1c. Create temporary faces representing sides of volumes if correspondent
9882     //     face does not exist
9883     // -------------------------------------------------------------------------
9884
9885     if ( !volSet->empty() ) {
9886       //int nodeSetSize = nodeSet->size();
9887
9888       // loop on given volumes
9889       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9890         SMDS_VolumeTool vol (*vIt);
9891         // loop on volume faces: find free faces
9892         // --------------------------------------
9893         list<const SMDS_MeshElement* > freeFaceList;
9894         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9895           if ( !vol.IsFreeFace( iFace ))
9896             continue;
9897           // check if there is already a face with same nodes in a face set
9898           const SMDS_MeshElement* aFreeFace = 0;
9899           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9900           int nbNodes = vol.NbFaceNodes( iFace );
9901           set <const SMDS_MeshNode*> faceNodeSet;
9902           vol.GetFaceNodes( iFace, faceNodeSet );
9903           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9904           if ( isNewFace ) {
9905             // no such a face is given but it still can exist, check it
9906             if ( nbNodes == 3 ) {
9907               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9908             }
9909             else if ( nbNodes == 4 ) {
9910               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9911             }
9912             else {
9913               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9914               aFreeFace = aMesh->FindFace(poly_nodes);
9915             }
9916           }
9917           if ( !aFreeFace ) {
9918             // create a temporary face
9919             if ( nbNodes == 3 ) {
9920               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9921               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9922             }
9923             else if ( nbNodes == 4 ) {
9924               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9925               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9926             }
9927             else {
9928               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9929               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9930               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9931             }
9932           }
9933           if ( aFreeFace ) {
9934             freeFaceList.push_back( aFreeFace );
9935             tempFaceList.push_back( aFreeFace );
9936           }
9937
9938         } // loop on faces of a volume
9939
9940         // choose one of several free faces
9941         // --------------------------------------
9942         if ( freeFaceList.size() > 1 ) {
9943           // choose a face having max nb of nodes shared by other elems of a side
9944           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9945           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9946           while ( fIt != freeFaceList.end() ) { // loop on free faces
9947             int nbSharedNodes = 0;
9948             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9949             while ( nodeIt->more() ) { // loop on free face nodes
9950               const SMDS_MeshNode* n =
9951                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9952               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9953               while ( invElemIt->more() ) {
9954                 const SMDS_MeshElement* e = invElemIt->next();
9955                 if ( faceSet->find( e ) != faceSet->end() )
9956                   nbSharedNodes++;
9957                 if ( elemSet->find( e ) != elemSet->end() )
9958                   nbSharedNodes++;
9959               }
9960             }
9961             if ( nbSharedNodes >= maxNbNodes ) {
9962               maxNbNodes = nbSharedNodes;
9963               fIt++;
9964             }
9965             else
9966               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9967           }
9968           if ( freeFaceList.size() > 1 )
9969           {
9970             // could not choose one face, use another way
9971             // choose a face most close to the bary center of the opposite side
9972             gp_XYZ aBC( 0., 0., 0. );
9973             set <const SMDS_MeshNode*> addedNodes;
9974             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9975             eIt = elemSet2->begin();
9976             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9977               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9978               while ( nodeIt->more() ) { // loop on free face nodes
9979                 const SMDS_MeshNode* n =
9980                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9981                 if ( addedNodes.insert( n ).second )
9982                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9983               }
9984             }
9985             aBC /= addedNodes.size();
9986             double minDist = DBL_MAX;
9987             fIt = freeFaceList.begin();
9988             while ( fIt != freeFaceList.end() ) { // loop on free faces
9989               double dist = 0;
9990               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9991               while ( nodeIt->more() ) { // loop on free face nodes
9992                 const SMDS_MeshNode* n =
9993                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9994                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9995                 dist += ( aBC - p ).SquareModulus();
9996               }
9997               if ( dist < minDist ) {
9998                 minDist = dist;
9999                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
10000               }
10001               else
10002                 fIt = freeFaceList.erase( fIt++ );
10003             }
10004           }
10005         } // choose one of several free faces of a volume
10006
10007         if ( freeFaceList.size() == 1 ) {
10008           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
10009           faceSet->insert( aFreeFace );
10010           // complete a node set with nodes of a found free face
10011           //           for ( iNode = 0; iNode < ; iNode++ )
10012           //             nodeSet->insert( fNodes[ iNode ] );
10013         }
10014
10015       } // loop on volumes of a side
10016
10017       //       // complete a set of faces if new nodes in a nodeSet appeared
10018       //       // ----------------------------------------------------------
10019       //       if ( nodeSetSize != nodeSet->size() ) {
10020       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10021       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10022       //           while ( fIt->more() ) { // loop on faces sharing a node
10023       //             const SMDS_MeshElement* f = fIt->next();
10024       //             if ( faceSet->find( f ) == faceSet->end() ) {
10025       //               // check if all nodes are in nodeSet and
10026       //               // complete setOfFaceNodeSet if they are
10027       //               set <const SMDS_MeshNode*> faceNodeSet;
10028       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10029       //               bool allInSet = true;
10030       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10031       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10032       //                 if ( nodeSet->find( n ) == nodeSet->end() )
10033       //                   allInSet = false;
10034       //                 else
10035       //                   faceNodeSet.insert( n );
10036       //               }
10037       //               if ( allInSet ) {
10038       //                 faceSet->insert( f );
10039       //                 setOfFaceNodeSet.insert( faceNodeSet );
10040       //               }
10041       //             }
10042       //           }
10043       //         }
10044       //       }
10045     } // Create temporary faces, if there are volumes given
10046   } // loop on sides
10047
10048   if ( faceSet1.size() != faceSet2.size() ) {
10049     // delete temporary faces: they are in reverseElements of actual nodes
10050 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10051 //    while ( tmpFaceIt->more() )
10052 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10053 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10054 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10055 //      aMesh->RemoveElement(*tmpFaceIt);
10056     MESSAGE("Diff nb of faces");
10057     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10058   }
10059
10060   // ============================================================
10061   // 2. Find nodes to merge:
10062   //              bind a node to remove to a node to put instead
10063   // ============================================================
10064
10065   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10066   if ( theFirstNode1 != theFirstNode2 )
10067     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10068   if ( theSecondNode1 != theSecondNode2 )
10069     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10070
10071   LinkID_Gen aLinkID_Gen( GetMeshDS() );
10072   set< long > linkIdSet; // links to process
10073   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10074
10075   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10076   list< NLink > linkList[2];
10077   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10078   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10079   // loop on links in linkList; find faces by links and append links
10080   // of the found faces to linkList
10081   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10082   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10083     NLink link[] = { *linkIt[0], *linkIt[1] };
10084     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10085     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10086       continue;
10087
10088     // by links, find faces in the face sets,
10089     // and find indices of link nodes in the found faces;
10090     // in a face set, there is only one or no face sharing a link
10091     // ---------------------------------------------------------------
10092
10093     const SMDS_MeshElement* face[] = { 0, 0 };
10094     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10095     vector<const SMDS_MeshNode*> fnodes1(9);
10096     vector<const SMDS_MeshNode*> fnodes2(9);
10097     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10098     vector<const SMDS_MeshNode*> notLinkNodes1(6);
10099     vector<const SMDS_MeshNode*> notLinkNodes2(6);
10100     int iLinkNode[2][2];
10101     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10102       const SMDS_MeshNode* n1 = link[iSide].first;
10103       const SMDS_MeshNode* n2 = link[iSide].second;
10104       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10105       set< const SMDS_MeshElement* > fMap;
10106       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10107         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10108         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10109         while ( fIt->more() ) { // loop on faces sharing a node
10110           const SMDS_MeshElement* f = fIt->next();
10111           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10112               ! fMap.insert( f ).second ) // f encounters twice
10113           {
10114             if ( face[ iSide ] ) {
10115               MESSAGE( "2 faces per link " );
10116               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10117               break;
10118             }
10119             face[ iSide ] = f;
10120             faceSet->erase( f );
10121             // get face nodes and find ones of a link
10122             iNode = 0;
10123             int nbl = -1;
10124             if(f->IsPoly()) {
10125               if(iSide==0) {
10126                 fnodes1.resize(f->NbNodes()+1);
10127                 notLinkNodes1.resize(f->NbNodes()-2);
10128               }
10129               else {
10130                 fnodes2.resize(f->NbNodes()+1);
10131                 notLinkNodes2.resize(f->NbNodes()-2);
10132               }
10133             }
10134             if(!f->IsQuadratic()) {
10135               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10136               while ( nIt->more() ) {
10137                 const SMDS_MeshNode* n =
10138                   static_cast<const SMDS_MeshNode*>( nIt->next() );
10139                 if ( n == n1 ) {
10140                   iLinkNode[ iSide ][ 0 ] = iNode;
10141                 }
10142                 else if ( n == n2 ) {
10143                   iLinkNode[ iSide ][ 1 ] = iNode;
10144                 }
10145                 //else if ( notLinkNodes[ iSide ][ 0 ] )
10146                 //  notLinkNodes[ iSide ][ 1 ] = n;
10147                 //else
10148                 //  notLinkNodes[ iSide ][ 0 ] = n;
10149                 else {
10150                   nbl++;
10151                   if(iSide==0)
10152                     notLinkNodes1[nbl] = n;
10153                   //notLinkNodes1.push_back(n);
10154                   else
10155                     notLinkNodes2[nbl] = n;
10156                   //notLinkNodes2.push_back(n);
10157                 }
10158                 //faceNodes[ iSide ][ iNode++ ] = n;
10159                 if(iSide==0) {
10160                   fnodes1[iNode++] = n;
10161                 }
10162                 else {
10163                   fnodes2[iNode++] = n;
10164                 }
10165               }
10166             }
10167             else { // f->IsQuadratic()
10168               const SMDS_VtkFace* F =
10169                 dynamic_cast<const SMDS_VtkFace*>(f);
10170               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10171               // use special nodes iterator
10172               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10173               while ( anIter->more() ) {
10174                 const SMDS_MeshNode* n =
10175                   static_cast<const SMDS_MeshNode*>( anIter->next() );
10176                 if ( n == n1 ) {
10177                   iLinkNode[ iSide ][ 0 ] = iNode;
10178                 }
10179                 else if ( n == n2 ) {
10180                   iLinkNode[ iSide ][ 1 ] = iNode;
10181                 }
10182                 else {
10183                   nbl++;
10184                   if(iSide==0) {
10185                     notLinkNodes1[nbl] = n;
10186                   }
10187                   else {
10188                     notLinkNodes2[nbl] = n;
10189                   }
10190                 }
10191                 if(iSide==0) {
10192                   fnodes1[iNode++] = n;
10193                 }
10194                 else {
10195                   fnodes2[iNode++] = n;
10196                 }
10197               }
10198             }
10199             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10200             if(iSide==0) {
10201               fnodes1[iNode] = fnodes1[0];
10202             }
10203             else {
10204               fnodes2[iNode] = fnodes1[0];
10205             }
10206           }
10207         }
10208       }
10209     }
10210
10211     // check similarity of elements of the sides
10212     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10213       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10214       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10215         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10216       }
10217       else {
10218         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10219       }
10220       break; // do not return because it s necessary to remove tmp faces
10221     }
10222
10223     // set nodes to merge
10224     // -------------------
10225
10226     if ( face[0] && face[1] )  {
10227       int nbNodes = face[0]->NbNodes();
10228       if ( nbNodes != face[1]->NbNodes() ) {
10229         MESSAGE("Diff nb of face nodes");
10230         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10231         break; // do not return because it s necessary to remove tmp faces
10232       }
10233       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10234       if ( nbNodes == 3 ) {
10235         //nReplaceMap.insert( TNodeNodeMap::value_type
10236         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10237         nReplaceMap.insert( TNodeNodeMap::value_type
10238                             ( notLinkNodes1[0], notLinkNodes2[0] ));
10239       }
10240       else {
10241         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10242           // analyse link orientation in faces
10243           int i1 = iLinkNode[ iSide ][ 0 ];
10244           int i2 = iLinkNode[ iSide ][ 1 ];
10245           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10246           // if notLinkNodes are the first and the last ones, then
10247           // their order does not correspond to the link orientation
10248           if (( i1 == 1 && i2 == 2 ) ||
10249               ( i1 == 2 && i2 == 1 ))
10250             reverse[ iSide ] = !reverse[ iSide ];
10251         }
10252         if ( reverse[0] == reverse[1] ) {
10253           //nReplaceMap.insert( TNodeNodeMap::value_type
10254           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10255           //nReplaceMap.insert( TNodeNodeMap::value_type
10256           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10257           for(int nn=0; nn<nbNodes-2; nn++) {
10258             nReplaceMap.insert( TNodeNodeMap::value_type
10259                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10260           }
10261         }
10262         else {
10263           //nReplaceMap.insert( TNodeNodeMap::value_type
10264           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10265           //nReplaceMap.insert( TNodeNodeMap::value_type
10266           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10267           for(int nn=0; nn<nbNodes-2; nn++) {
10268             nReplaceMap.insert( TNodeNodeMap::value_type
10269                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10270           }
10271         }
10272       }
10273
10274       // add other links of the faces to linkList
10275       // -----------------------------------------
10276
10277       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10278       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10279         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10280         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10281         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10282         if ( !iter_isnew.second ) { // already in a set: no need to process
10283           linkIdSet.erase( iter_isnew.first );
10284         }
10285         else // new in set == encountered for the first time: add
10286         {
10287           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10288           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10289           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10290           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10291           linkList[0].push_back ( NLink( n1, n2 ));
10292           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10293         }
10294       }
10295     } // 2 faces found
10296   } // loop on link lists
10297
10298   if ( aResult == SEW_OK &&
10299        ( linkIt[0] != linkList[0].end() ||
10300          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10301     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10302              " " << (faceSetPtr[1]->empty()));
10303     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10304   }
10305
10306   // ====================================================================
10307   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10308   // ====================================================================
10309
10310   // delete temporary faces: they are in reverseElements of actual nodes
10311 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10312 //  while ( tmpFaceIt->more() )
10313 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10314 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10315 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10316 //    aMesh->RemoveElement(*tmpFaceIt);
10317
10318   if ( aResult != SEW_OK)
10319     return aResult;
10320
10321   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10322   // loop on nodes replacement map
10323   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10324   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10325     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10326       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10327       nodeIDsToRemove.push_back( nToRemove->GetID() );
10328       // loop on elements sharing nToRemove
10329       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10330       while ( invElemIt->more() ) {
10331         const SMDS_MeshElement* e = invElemIt->next();
10332         // get a new suite of nodes: make replacement
10333         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10334         vector< const SMDS_MeshNode*> nodes( nbNodes );
10335         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10336         while ( nIt->more() ) {
10337           const SMDS_MeshNode* n =
10338             static_cast<const SMDS_MeshNode*>( nIt->next() );
10339           nnIt = nReplaceMap.find( n );
10340           if ( nnIt != nReplaceMap.end() ) {
10341             nbReplaced++;
10342             n = (*nnIt).second;
10343           }
10344           nodes[ i++ ] = n;
10345         }
10346         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10347         //         elemIDsToRemove.push_back( e->GetID() );
10348         //       else
10349         if ( nbReplaced )
10350           {
10351             SMDSAbs_ElementType etyp = e->GetType();
10352             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10353             if (newElem)
10354               {
10355                 myLastCreatedElems.Append(newElem);
10356                 AddToSameGroups(newElem, e, aMesh);
10357                 int aShapeId = e->getshapeId();
10358                 if ( aShapeId )
10359                   {
10360                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10361                   }
10362               }
10363             aMesh->RemoveElement(e);
10364           }
10365       }
10366     }
10367
10368   Remove( nodeIDsToRemove, true );
10369
10370   return aResult;
10371 }
10372
10373 //================================================================================
10374 /*!
10375  * \brief Find corresponding nodes in two sets of faces
10376  * \param theSide1 - first face set
10377  * \param theSide2 - second first face
10378  * \param theFirstNode1 - a boundary node of set 1
10379  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10380  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10381  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10382  * \param nReplaceMap - output map of corresponding nodes
10383  * \return bool  - is a success or not
10384  */
10385 //================================================================================
10386
10387 #ifdef _DEBUG_
10388 //#define DEBUG_MATCHING_NODES
10389 #endif
10390
10391 SMESH_MeshEditor::Sew_Error
10392 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10393                                     set<const SMDS_MeshElement*>& theSide2,
10394                                     const SMDS_MeshNode*          theFirstNode1,
10395                                     const SMDS_MeshNode*          theFirstNode2,
10396                                     const SMDS_MeshNode*          theSecondNode1,
10397                                     const SMDS_MeshNode*          theSecondNode2,
10398                                     TNodeNodeMap &                nReplaceMap)
10399 {
10400   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10401
10402   nReplaceMap.clear();
10403   if ( theFirstNode1 != theFirstNode2 )
10404     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10405   if ( theSecondNode1 != theSecondNode2 )
10406     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10407
10408   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10409   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10410
10411   list< NLink > linkList[2];
10412   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10413   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10414
10415   // loop on links in linkList; find faces by links and append links
10416   // of the found faces to linkList
10417   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10418   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10419     NLink link[] = { *linkIt[0], *linkIt[1] };
10420     if ( linkSet.find( link[0] ) == linkSet.end() )
10421       continue;
10422
10423     // by links, find faces in the face sets,
10424     // and find indices of link nodes in the found faces;
10425     // in a face set, there is only one or no face sharing a link
10426     // ---------------------------------------------------------------
10427
10428     const SMDS_MeshElement* face[] = { 0, 0 };
10429     list<const SMDS_MeshNode*> notLinkNodes[2];
10430     //bool reverse[] = { false, false }; // order of notLinkNodes
10431     int nbNodes[2];
10432     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10433     {
10434       const SMDS_MeshNode* n1 = link[iSide].first;
10435       const SMDS_MeshNode* n2 = link[iSide].second;
10436       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10437       set< const SMDS_MeshElement* > facesOfNode1;
10438       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10439       {
10440         // during a loop of the first node, we find all faces around n1,
10441         // during a loop of the second node, we find one face sharing both n1 and n2
10442         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10443         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10444         while ( fIt->more() ) { // loop on faces sharing a node
10445           const SMDS_MeshElement* f = fIt->next();
10446           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10447               ! facesOfNode1.insert( f ).second ) // f encounters twice
10448           {
10449             if ( face[ iSide ] ) {
10450               MESSAGE( "2 faces per link " );
10451               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10452             }
10453             face[ iSide ] = f;
10454             faceSet->erase( f );
10455
10456             // get not link nodes
10457             int nbN = f->NbNodes();
10458             if ( f->IsQuadratic() )
10459               nbN /= 2;
10460             nbNodes[ iSide ] = nbN;
10461             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10462             int i1 = f->GetNodeIndex( n1 );
10463             int i2 = f->GetNodeIndex( n2 );
10464             int iEnd = nbN, iBeg = -1, iDelta = 1;
10465             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10466             if ( reverse ) {
10467               std::swap( iEnd, iBeg ); iDelta = -1;
10468             }
10469             int i = i2;
10470             while ( true ) {
10471               i += iDelta;
10472               if ( i == iEnd ) i = iBeg + iDelta;
10473               if ( i == i1 ) break;
10474               nodes.push_back ( f->GetNode( i ) );
10475             }
10476           }
10477         }
10478       }
10479     }
10480     // check similarity of elements of the sides
10481     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10482       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10483       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10484         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10485       }
10486       else {
10487         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10488       }
10489     }
10490
10491     // set nodes to merge
10492     // -------------------
10493
10494     if ( face[0] && face[1] )  {
10495       if ( nbNodes[0] != nbNodes[1] ) {
10496         MESSAGE("Diff nb of face nodes");
10497         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10498       }
10499 #ifdef DEBUG_MATCHING_NODES
10500       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10501                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10502                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10503 #endif
10504       int nbN = nbNodes[0];
10505       {
10506         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10507         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10508         for ( int i = 0 ; i < nbN - 2; ++i ) {
10509 #ifdef DEBUG_MATCHING_NODES
10510           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10511 #endif
10512           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10513         }
10514       }
10515
10516       // add other links of the face 1 to linkList
10517       // -----------------------------------------
10518
10519       const SMDS_MeshElement* f0 = face[0];
10520       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10521       for ( int i = 0; i < nbN; i++ )
10522       {
10523         const SMDS_MeshNode* n2 = f0->GetNode( i );
10524         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10525           linkSet.insert( SMESH_TLink( n1, n2 ));
10526         if ( !iter_isnew.second ) { // already in a set: no need to process
10527           linkSet.erase( iter_isnew.first );
10528         }
10529         else // new in set == encountered for the first time: add
10530         {
10531 #ifdef DEBUG_MATCHING_NODES
10532           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10533                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10534 #endif
10535           linkList[0].push_back ( NLink( n1, n2 ));
10536           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10537         }
10538         n1 = n2;
10539       }
10540     } // 2 faces found
10541   } // loop on link lists
10542
10543   return SEW_OK;
10544 }
10545
10546 //================================================================================
10547 /*!
10548   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10549   \param theElems - the list of elements (edges or faces) to be replicated
10550   The nodes for duplication could be found from these elements
10551   \param theNodesNot - list of nodes to NOT replicate
10552   \param theAffectedElems - the list of elements (cells and edges) to which the 
10553   replicated nodes should be associated to.
10554   \return TRUE if operation has been completed successfully, FALSE otherwise
10555 */
10556 //================================================================================
10557
10558 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10559                                     const TIDSortedElemSet& theNodesNot,
10560                                     const TIDSortedElemSet& theAffectedElems )
10561 {
10562   myLastCreatedElems.Clear();
10563   myLastCreatedNodes.Clear();
10564
10565   if ( theElems.size() == 0 )
10566     return false;
10567
10568   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10569   if ( !aMeshDS )
10570     return false;
10571
10572   bool res = false;
10573   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10574   // duplicate elements and nodes
10575   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10576   // replce nodes by duplications
10577   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10578   return res;
10579 }
10580
10581 //================================================================================
10582 /*!
10583   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10584   \param theMeshDS - mesh instance
10585   \param theElems - the elements replicated or modified (nodes should be changed)
10586   \param theNodesNot - nodes to NOT replicate
10587   \param theNodeNodeMap - relation of old node to new created node
10588   \param theIsDoubleElem - flag os to replicate element or modify
10589   \return TRUE if operation has been completed successfully, FALSE otherwise
10590 */
10591 //================================================================================
10592
10593 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10594                                     const TIDSortedElemSet& theElems,
10595                                     const TIDSortedElemSet& theNodesNot,
10596                                     std::map< const SMDS_MeshNode*,
10597                                     const SMDS_MeshNode* >& theNodeNodeMap,
10598                                     const bool theIsDoubleElem )
10599 {
10600   MESSAGE("doubleNodes");
10601   // iterate on through element and duplicate them (by nodes duplication)
10602   bool res = false;
10603   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10604   for ( ;  elemItr != theElems.end(); ++elemItr )
10605   {
10606     const SMDS_MeshElement* anElem = *elemItr;
10607     if (!anElem)
10608       continue;
10609
10610     bool isDuplicate = false;
10611     // duplicate nodes to duplicate element
10612     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10613     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10614     int ind = 0;
10615     while ( anIter->more() ) 
10616     { 
10617
10618       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10619       SMDS_MeshNode* aNewNode = aCurrNode;
10620       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10621         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10622       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10623       {
10624         // duplicate node
10625         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10626         theNodeNodeMap[ aCurrNode ] = aNewNode;
10627         myLastCreatedNodes.Append( aNewNode );
10628       }
10629       isDuplicate |= (aCurrNode != aNewNode);
10630       newNodes[ ind++ ] = aNewNode;
10631     }
10632     if ( !isDuplicate )
10633       continue;
10634
10635     if ( theIsDoubleElem )
10636       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10637     else
10638       {
10639       MESSAGE("ChangeElementNodes");
10640       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10641       }
10642     res = true;
10643   }
10644   return res;
10645 }
10646
10647 //================================================================================
10648 /*!
10649   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10650   \param theNodes - identifiers of nodes to be doubled
10651   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10652          nodes. If list of element identifiers is empty then nodes are doubled but 
10653          they not assigned to elements
10654   \return TRUE if operation has been completed successfully, FALSE otherwise
10655 */
10656 //================================================================================
10657
10658 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10659                                     const std::list< int >& theListOfModifiedElems )
10660 {
10661   MESSAGE("DoubleNodes");
10662   myLastCreatedElems.Clear();
10663   myLastCreatedNodes.Clear();
10664
10665   if ( theListOfNodes.size() == 0 )
10666     return false;
10667
10668   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10669   if ( !aMeshDS )
10670     return false;
10671
10672   // iterate through nodes and duplicate them
10673
10674   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10675
10676   std::list< int >::const_iterator aNodeIter;
10677   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10678   {
10679     int aCurr = *aNodeIter;
10680     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10681     if ( !aNode )
10682       continue;
10683
10684     // duplicate node
10685
10686     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10687     if ( aNewNode )
10688     {
10689       anOldNodeToNewNode[ aNode ] = aNewNode;
10690       myLastCreatedNodes.Append( aNewNode );
10691     }
10692   }
10693
10694   // Create map of new nodes for modified elements
10695
10696   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10697
10698   std::list< int >::const_iterator anElemIter;
10699   for ( anElemIter = theListOfModifiedElems.begin(); 
10700         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10701   {
10702     int aCurr = *anElemIter;
10703     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10704     if ( !anElem )
10705       continue;
10706
10707     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10708
10709     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10710     int ind = 0;
10711     while ( anIter->more() ) 
10712     { 
10713       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10714       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10715       {
10716         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10717         aNodeArr[ ind++ ] = aNewNode;
10718       }
10719       else
10720         aNodeArr[ ind++ ] = aCurrNode;
10721     }
10722     anElemToNodes[ anElem ] = aNodeArr;
10723   }
10724
10725   // Change nodes of elements  
10726
10727   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10728     anElemToNodesIter = anElemToNodes.begin();
10729   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10730   {
10731     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10732     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10733     if ( anElem )
10734       {
10735       MESSAGE("ChangeElementNodes");
10736       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10737       }
10738   }
10739
10740   return true;
10741 }
10742
10743 namespace {
10744
10745   //================================================================================
10746   /*!
10747   \brief Check if element located inside shape
10748   \return TRUE if IN or ON shape, FALSE otherwise
10749   */
10750   //================================================================================
10751
10752   template<class Classifier>
10753   bool isInside(const SMDS_MeshElement* theElem,
10754                 Classifier&             theClassifier,
10755                 const double            theTol)
10756   {
10757     gp_XYZ centerXYZ (0, 0, 0);
10758     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10759     while (aNodeItr->more())
10760       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10761
10762     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10763     theClassifier.Perform(aPnt, theTol);
10764     TopAbs_State aState = theClassifier.State();
10765     return (aState == TopAbs_IN || aState == TopAbs_ON );
10766   }
10767
10768   //================================================================================
10769   /*!
10770    * \brief Classifier of the 3D point on the TopoDS_Face
10771    *        with interaface suitable for isInside()
10772    */
10773   //================================================================================
10774
10775   struct _FaceClassifier
10776   {
10777     Extrema_ExtPS       _extremum;
10778     BRepAdaptor_Surface _surface;
10779     TopAbs_State        _state;
10780
10781     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10782     {
10783       _extremum.Initialize( _surface,
10784                             _surface.FirstUParameter(), _surface.LastUParameter(),
10785                             _surface.FirstVParameter(), _surface.LastVParameter(),
10786                             _surface.Tolerance(), _surface.Tolerance() );
10787     }
10788     void Perform(const gp_Pnt& aPnt, double theTol)
10789     {
10790       _state = TopAbs_OUT;
10791       _extremum.Perform(aPnt);
10792       if ( _extremum.IsDone() )
10793         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10794 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
10795           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10796 #else
10797           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10798 #endif
10799     }
10800     TopAbs_State State() const
10801     {
10802       return _state;
10803     }
10804   };
10805 }
10806
10807 //================================================================================
10808 /*!
10809   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10810   \param theElems - group of of elements (edges or faces) to be replicated
10811   \param theNodesNot - group of nodes not to replicate
10812   \param theShape - shape to detect affected elements (element which geometric center
10813   located on or inside shape).
10814   The replicated nodes should be associated to affected elements.
10815   \return TRUE if operation has been completed successfully, FALSE otherwise
10816 */
10817 //================================================================================
10818
10819 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10820                                             const TIDSortedElemSet& theNodesNot,
10821                                             const TopoDS_Shape&     theShape )
10822 {
10823   if ( theShape.IsNull() )
10824     return false;
10825
10826   const double aTol = Precision::Confusion();
10827   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10828   auto_ptr<_FaceClassifier>              aFaceClassifier;
10829   if ( theShape.ShapeType() == TopAbs_SOLID )
10830   {
10831     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10832     bsc3d->PerformInfinitePoint(aTol);
10833   }
10834   else if (theShape.ShapeType() == TopAbs_FACE )
10835   {
10836     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10837   }
10838
10839   // iterates on indicated elements and get elements by back references from their nodes
10840   TIDSortedElemSet anAffected;
10841   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10842   for ( ;  elemItr != theElems.end(); ++elemItr )
10843   {
10844     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10845     if (!anElem)
10846       continue;
10847
10848     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10849     while ( nodeItr->more() )
10850     {
10851       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10852       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10853         continue;
10854       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10855       while ( backElemItr->more() )
10856       {
10857         const SMDS_MeshElement* curElem = backElemItr->next();
10858         if ( curElem && theElems.find(curElem) == theElems.end() &&
10859              ( bsc3d.get() ?
10860                isInside( curElem, *bsc3d, aTol ) :
10861                isInside( curElem, *aFaceClassifier, aTol )))
10862           anAffected.insert( curElem );
10863       }
10864     }
10865   }
10866   return DoubleNodes( theElems, theNodesNot, anAffected );
10867 }
10868
10869 /*!
10870  *  \brief compute an oriented angle between two planes defined by four points.
10871  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10872  *  @param p0 base of the rotation axe
10873  *  @param p1 extremity of the rotation axe
10874  *  @param g1 belongs to the first plane
10875  *  @param g2 belongs to the second plane
10876  */
10877 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10878 {
10879 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10880 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10881 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10882 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10883   gp_Vec vref(p0, p1);
10884   gp_Vec v1(p0, g1);
10885   gp_Vec v2(p0, g2);
10886   gp_Vec n1 = vref.Crossed(v1);
10887   gp_Vec n2 = vref.Crossed(v2);
10888   return n2.AngleWithRef(n1, vref);
10889 }
10890
10891 /*!
10892  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10893  * The list of groups must describe a partition of the mesh volumes.
10894  * The nodes of the internal faces at the boundaries of the groups are doubled.
10895  * In option, the internal faces are replaced by flat elements.
10896  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10897  * The flat elements are stored in groups of volumes.
10898  * @param theElems - list of groups of volumes, where a group of volume is a set of
10899  * SMDS_MeshElements sorted by Id.
10900  * @param createJointElems - if TRUE, create the elements
10901  * @return TRUE if operation has been completed successfully, FALSE otherwise
10902  */
10903 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10904                                                      bool createJointElems)
10905 {
10906   MESSAGE("----------------------------------------------");
10907   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10908   MESSAGE("----------------------------------------------");
10909
10910   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10911   meshDS->BuildDownWardConnectivity(true);
10912   CHRONO(50);
10913   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10914
10915   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10916   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10917   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10918
10919   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10920   std::map<int,int>celldom; // cell vtkId --> domain
10921   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10922   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10923   faceDomains.clear();
10924   celldom.clear();
10925   cellDomains.clear();
10926   nodeDomains.clear();
10927   std::map<int,int> emptyMap;
10928   std::set<int> emptySet;
10929   emptyMap.clear();
10930
10931   for (int idom = 0; idom < theElems.size(); idom++)
10932     {
10933
10934       // --- build a map (face to duplicate --> volume to modify)
10935       //     with all the faces shared by 2 domains (group of elements)
10936       //     and corresponding volume of this domain, for each shared face.
10937       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10938
10939       const TIDSortedElemSet& domain = theElems[idom];
10940       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10941       for (; elemItr != domain.end(); ++elemItr)
10942         {
10943           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10944           if (!anElem)
10945             continue;
10946           int vtkId = anElem->getVtkId();
10947           int neighborsVtkIds[NBMAXNEIGHBORS];
10948           int downIds[NBMAXNEIGHBORS];
10949           unsigned char downTypes[NBMAXNEIGHBORS];
10950           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10951           for (int n = 0; n < nbNeighbors; n++)
10952             {
10953               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10954               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10955               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10956                 {
10957                   DownIdType face(downIds[n], downTypes[n]);
10958                   if (!faceDomains.count(face))
10959                     faceDomains[face] = emptyMap; // create an empty entry for face
10960                   if (!faceDomains[face].count(idom))
10961                     {
10962                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10963                       celldom[vtkId] = idom;
10964                     }
10965                 }
10966             }
10967         }
10968     }
10969
10970   //MESSAGE("Number of shared faces " << faceDomains.size());
10971   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10972
10973   // --- explore the shared faces domain by domain,
10974   //     explore the nodes of the face and see if they belong to a cell in the domain,
10975   //     which has only a node or an edge on the border (not a shared face)
10976
10977   for (int idomain = 0; idomain < theElems.size(); idomain++)
10978     {
10979       const TIDSortedElemSet& domain = theElems[idomain];
10980       itface = faceDomains.begin();
10981       for (; itface != faceDomains.end(); ++itface)
10982         {
10983           std::map<int, int> domvol = itface->second;
10984           if (!domvol.count(idomain))
10985             continue;
10986           DownIdType face = itface->first;
10987           //MESSAGE(" --- face " << face.cellId);
10988           std::set<int> oldNodes;
10989           oldNodes.clear();
10990           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10991           std::set<int>::iterator itn = oldNodes.begin();
10992           for (; itn != oldNodes.end(); ++itn)
10993             {
10994               int oldId = *itn;
10995               //MESSAGE("     node " << oldId);
10996               std::set<int> cells;
10997               cells.clear();
10998               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10999               for (int i=0; i<l.ncells; i++)
11000                 {
11001                   int vtkId = l.cells[i];
11002                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
11003                   if (!domain.count(anElem))
11004                     continue;
11005                   int vtkType = grid->GetCellType(vtkId);
11006                   int downId = grid->CellIdToDownId(vtkId);
11007                   if (downId < 0)
11008                     {
11009                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
11010                       continue; // not OK at this stage of the algorithm:
11011                                 //no cells created after BuildDownWardConnectivity
11012                     }
11013                   DownIdType aCell(downId, vtkType);
11014                   if (celldom.count(vtkId))
11015                     continue;
11016                   cellDomains[aCell][idomain] = vtkId;
11017                   celldom[vtkId] = idomain;
11018                 }
11019             }
11020         }
11021     }
11022
11023   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
11024   //     for each shared face, get the nodes
11025   //     for each node, for each domain of the face, create a clone of the node
11026
11027   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
11028   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
11029   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
11030
11031   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
11032   std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
11033
11034   for (int idomain = 0; idomain < theElems.size(); idomain++)
11035     {
11036       itface = faceDomains.begin();
11037       for (; itface != faceDomains.end(); ++itface)
11038         {
11039           std::map<int, int> domvol = itface->second;
11040           if (!domvol.count(idomain))
11041             continue;
11042           DownIdType face = itface->first;
11043           //MESSAGE(" --- face " << face.cellId);
11044           std::set<int> oldNodes;
11045           oldNodes.clear();
11046           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11047           bool isMultipleDetected = false;
11048           std::set<int>::iterator itn = oldNodes.begin();
11049           for (; itn != oldNodes.end(); ++itn)
11050             {
11051               int oldId = *itn;
11052               //MESSAGE("     node " << oldId);
11053               if (!nodeDomains.count(oldId))
11054                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11055               if (nodeDomains[oldId].empty())
11056                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11057               std::map<int, int>::iterator itdom = domvol.begin();
11058               for (; itdom != domvol.end(); ++itdom)
11059                 {
11060                   int idom = itdom->first;
11061                   //MESSAGE("         domain " << idom);
11062                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
11063                     {
11064                       if (nodeDomains[oldId].size() >= 2) // a multiple node
11065                         {
11066                           vector<int> orderedDoms;
11067                           //MESSAGE("multiple node " << oldId);
11068                           isMultipleDetected =true;
11069                           if (mutipleNodes.count(oldId))
11070                             orderedDoms = mutipleNodes[oldId];
11071                           else
11072                             {
11073                               map<int,int>::iterator it = nodeDomains[oldId].begin();
11074                               for (; it != nodeDomains[oldId].end(); ++it)
11075                                 orderedDoms.push_back(it->first);
11076                             }
11077                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
11078                           //stringstream txt;
11079                           //for (int i=0; i<orderedDoms.size(); i++)
11080                           //  txt << orderedDoms[i] << " ";
11081                           //MESSAGE("orderedDoms " << txt.str());
11082                           mutipleNodes[oldId] = orderedDoms;
11083                         }
11084                       double *coords = grid->GetPoint(oldId);
11085                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11086                       int newId = newNode->getVtkId();
11087                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
11088                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11089                     }
11090                   if (nodeDomains[oldId].size() >= 3)
11091                     {
11092                       //MESSAGE("confirm multiple node " << oldId);
11093                       isMultipleDetected =true;
11094                     }
11095                 }
11096             }
11097           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11098             {
11099               //MESSAGE("multiple Nodes detected on a shared face");
11100               int downId = itface->first.cellId;
11101               unsigned char cellType = itface->first.cellType;
11102               int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11103               const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11104               const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11105               for (int ie =0; ie < nbEdges; ie++)
11106                 {
11107                   int nodes[3];
11108                   int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11109                   if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11110                     {
11111                       vector<int> vn0 = mutipleNodes[nodes[0]];
11112                       vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11113                       sort( vn0.begin(), vn0.end() );
11114                       sort( vn1.begin(), vn1.end() );
11115                       if (vn0 == vn1)
11116                         {
11117                           //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11118                           double *coords = grid->GetPoint(nodes[0]);
11119                           gp_Pnt p0(coords[0], coords[1], coords[2]);
11120                           coords = grid->GetPoint(nodes[nbNodes - 1]);
11121                           gp_Pnt p1(coords[0], coords[1], coords[2]);
11122                           gp_Pnt gref;
11123                           int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11124                           map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11125                           map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11126                           int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11127                           for (int id=0; id < vn0.size(); id++)
11128                             {
11129                               int idom = vn0[id];
11130                               for (int ivol=0; ivol<nbvol; ivol++)
11131                                 {
11132                                   int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11133                                   SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11134                                   if (theElems[idom].count(elem))
11135                                     {
11136                                       SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11137                                       domvol[idom] = svol;
11138                                       //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11139                                       double values[3];
11140                                       vtkIdType npts = 0;
11141                                       vtkIdType* pts = 0;
11142                                       grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11143                                       SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11144                                       if (id ==0)
11145                                         {
11146                                           gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11147                                           angleDom[idom] = 0;
11148                                         }
11149                                       else
11150                                         {
11151                                           gp_Pnt g(values[0], values[1], values[2]);
11152                                           angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11153                                           //MESSAGE("  angle=" << angleDom[idom]);
11154                                         }
11155                                       break;
11156                                     }
11157                                 }
11158                             }
11159                           map<double, int> sortedDom; // sort domains by angle
11160                           for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11161                             sortedDom[ia->second] = ia->first;
11162                           vector<int> vnodes;
11163                           vector<int> vdom;
11164                           for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11165                             {
11166                               vdom.push_back(ib->second);
11167                               //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11168                             }
11169                           for (int ino = 0; ino < nbNodes; ino++)
11170                             vnodes.push_back(nodes[ino]);
11171                           edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11172                         }
11173                     }
11174                 }
11175             }
11176         }
11177     }
11178
11179   // --- iterate on shared faces (volumes to modify, face to extrude)
11180   //     get node id's of the face (id SMDS = id VTK)
11181   //     create flat element with old and new nodes if requested
11182
11183   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11184   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11185
11186   std::map<int, std::map<long,int> > nodeQuadDomains;
11187   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11188
11189   if (createJointElems)
11190     {
11191       itface = faceDomains.begin();
11192       for (; itface != faceDomains.end(); ++itface)
11193         {
11194           DownIdType face = itface->first;
11195           std::set<int> oldNodes;
11196           std::set<int>::iterator itn;
11197           oldNodes.clear();
11198           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11199
11200           std::map<int, int> domvol = itface->second;
11201           std::map<int, int>::iterator itdom = domvol.begin();
11202           int dom1 = itdom->first;
11203           int vtkVolId = itdom->second;
11204           itdom++;
11205           int dom2 = itdom->first;
11206           SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11207                                                              nodeQuadDomains);
11208           stringstream grpname;
11209           grpname << "j_";
11210           if (dom1 < dom2)
11211             grpname << dom1 << "_" << dom2;
11212           else
11213             grpname << dom2 << "_" << dom1;
11214           int idg;
11215           string namegrp = grpname.str();
11216           if (!mapOfJunctionGroups.count(namegrp))
11217             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11218           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11219           if (sgrp)
11220             sgrp->Add(vol->GetID());
11221         }
11222     }
11223
11224   // --- create volumes on multiple domain intersection if requested
11225   //     iterate on edgesMultiDomains
11226
11227   if (createJointElems)
11228     {
11229       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11230       for (; ite != edgesMultiDomains.end(); ++ite)
11231         {
11232           vector<int> nodes = ite->first;
11233           vector<int> orderDom = ite->second;
11234           vector<vtkIdType> orderedNodes;
11235           if (nodes.size() == 2)
11236             {
11237               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11238               for (int ino=0; ino < nodes.size(); ino++)
11239                 if (orderDom.size() == 3)
11240                   for (int idom = 0; idom <orderDom.size(); idom++)
11241                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11242                 else
11243                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11244                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11245               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11246
11247               stringstream grpname;
11248               grpname << "mj_";
11249               grpname << 0 << "_" << 0;
11250               int idg;
11251               string namegrp = grpname.str();
11252               if (!mapOfJunctionGroups.count(namegrp))
11253                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11254               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11255               if (sgrp)
11256                 sgrp->Add(vol->GetID());
11257             }
11258           else
11259             {
11260               //MESSAGE("Quadratic multiple joints not implemented");
11261               // TODO quadratic nodes
11262             }
11263         }
11264     }
11265
11266   // --- list the explicit faces and edges of the mesh that need to be modified,
11267   //     i.e. faces and edges built with one or more duplicated nodes.
11268   //     associate these faces or edges to their corresponding domain.
11269   //     only the first domain found is kept when a face or edge is shared
11270
11271   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11272   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11273   faceOrEdgeDom.clear();
11274   feDom.clear();
11275
11276   for (int idomain = 0; idomain < theElems.size(); idomain++)
11277     {
11278       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11279       for (; itnod != nodeDomains.end(); ++itnod)
11280         {
11281           int oldId = itnod->first;
11282           //MESSAGE("     node " << oldId);
11283           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11284           for (int i = 0; i < l.ncells; i++)
11285             {
11286               int vtkId = l.cells[i];
11287               int vtkType = grid->GetCellType(vtkId);
11288               int downId = grid->CellIdToDownId(vtkId);
11289               if (downId < 0)
11290                 continue; // new cells: not to be modified
11291               DownIdType aCell(downId, vtkType);
11292               int volParents[1000];
11293               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11294               for (int j = 0; j < nbvol; j++)
11295                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11296                   if (!feDom.count(vtkId))
11297                     {
11298                       feDom[vtkId] = idomain;
11299                       faceOrEdgeDom[aCell] = emptyMap;
11300                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11301                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11302                       //        << " type " << vtkType << " downId " << downId);
11303                     }
11304             }
11305         }
11306     }
11307
11308   // --- iterate on shared faces (volumes to modify, face to extrude)
11309   //     get node id's of the face
11310   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11311
11312   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11313   for (int m=0; m<3; m++)
11314     {
11315       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11316       itface = (*amap).begin();
11317       for (; itface != (*amap).end(); ++itface)
11318         {
11319           DownIdType face = itface->first;
11320           std::set<int> oldNodes;
11321           std::set<int>::iterator itn;
11322           oldNodes.clear();
11323           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11324           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11325           std::map<int, int> localClonedNodeIds;
11326
11327           std::map<int, int> domvol = itface->second;
11328           std::map<int, int>::iterator itdom = domvol.begin();
11329           for (; itdom != domvol.end(); ++itdom)
11330             {
11331               int idom = itdom->first;
11332               int vtkVolId = itdom->second;
11333               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11334               localClonedNodeIds.clear();
11335               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11336                 {
11337                   int oldId = *itn;
11338                   if (nodeDomains[oldId].count(idom))
11339                     {
11340                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11341                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11342                     }
11343                 }
11344               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11345             }
11346         }
11347     }
11348
11349   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11350   grid->BuildLinks();
11351
11352   CHRONOSTOP(50);
11353   counters::stats();
11354   return true;
11355 }
11356
11357 /*!
11358  * \brief Double nodes on some external faces and create flat elements.
11359  * Flat elements are mainly used by some types of mechanic calculations.
11360  *
11361  * Each group of the list must be constituted of faces.
11362  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11363  * @param theElems - list of groups of faces, where a group of faces is a set of
11364  * SMDS_MeshElements sorted by Id.
11365  * @return TRUE if operation has been completed successfully, FALSE otherwise
11366  */
11367 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11368 {
11369   MESSAGE("-------------------------------------------------");
11370   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11371   MESSAGE("-------------------------------------------------");
11372
11373   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11374
11375   // --- For each group of faces
11376   //     duplicate the nodes, create a flat element based on the face
11377   //     replace the nodes of the faces by their clones
11378
11379   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11380   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11381   clonedNodes.clear();
11382   intermediateNodes.clear();
11383   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11384   mapOfJunctionGroups.clear();
11385
11386   for (int idom = 0; idom < theElems.size(); idom++)
11387     {
11388       const TIDSortedElemSet& domain = theElems[idom];
11389       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11390       for (; elemItr != domain.end(); ++elemItr)
11391         {
11392           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11393           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11394           if (!aFace)
11395             continue;
11396           // MESSAGE("aFace=" << aFace->GetID());
11397           bool isQuad = aFace->IsQuadratic();
11398           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11399
11400           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11401
11402           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11403           while (nodeIt->more())
11404             {
11405               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11406               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11407               if (isMedium)
11408                 ln2.push_back(node);
11409               else
11410                 ln0.push_back(node);
11411
11412               const SMDS_MeshNode* clone = 0;
11413               if (!clonedNodes.count(node))
11414                 {
11415                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11416                   clonedNodes[node] = clone;
11417                 }
11418               else
11419                 clone = clonedNodes[node];
11420
11421               if (isMedium)
11422                 ln3.push_back(clone);
11423               else
11424                 ln1.push_back(clone);
11425
11426               const SMDS_MeshNode* inter = 0;
11427               if (isQuad && (!isMedium))
11428                 {
11429                   if (!intermediateNodes.count(node))
11430                     {
11431                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11432                       intermediateNodes[node] = inter;
11433                     }
11434                   else
11435                     inter = intermediateNodes[node];
11436                   ln4.push_back(inter);
11437                 }
11438             }
11439
11440           // --- extrude the face
11441
11442           vector<const SMDS_MeshNode*> ln;
11443           SMDS_MeshVolume* vol = 0;
11444           vtkIdType aType = aFace->GetVtkType();
11445           switch (aType)
11446           {
11447             case VTK_TRIANGLE:
11448               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11449               // MESSAGE("vol prism " << vol->GetID());
11450               ln.push_back(ln1[0]);
11451               ln.push_back(ln1[1]);
11452               ln.push_back(ln1[2]);
11453               break;
11454             case VTK_QUAD:
11455               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11456               // MESSAGE("vol hexa " << vol->GetID());
11457               ln.push_back(ln1[0]);
11458               ln.push_back(ln1[1]);
11459               ln.push_back(ln1[2]);
11460               ln.push_back(ln1[3]);
11461               break;
11462             case VTK_QUADRATIC_TRIANGLE:
11463               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11464                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11465               // MESSAGE("vol quad prism " << vol->GetID());
11466               ln.push_back(ln1[0]);
11467               ln.push_back(ln1[1]);
11468               ln.push_back(ln1[2]);
11469               ln.push_back(ln3[0]);
11470               ln.push_back(ln3[1]);
11471               ln.push_back(ln3[2]);
11472               break;
11473             case VTK_QUADRATIC_QUAD:
11474 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11475 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11476 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11477               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11478                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11479                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11480               // MESSAGE("vol quad hexa " << vol->GetID());
11481               ln.push_back(ln1[0]);
11482               ln.push_back(ln1[1]);
11483               ln.push_back(ln1[2]);
11484               ln.push_back(ln1[3]);
11485               ln.push_back(ln3[0]);
11486               ln.push_back(ln3[1]);
11487               ln.push_back(ln3[2]);
11488               ln.push_back(ln3[3]);
11489               break;
11490             case VTK_POLYGON:
11491               break;
11492             default:
11493               break;
11494           }
11495
11496           if (vol)
11497             {
11498               stringstream grpname;
11499               grpname << "jf_";
11500               grpname << idom;
11501               int idg;
11502               string namegrp = grpname.str();
11503               if (!mapOfJunctionGroups.count(namegrp))
11504                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11505               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11506               if (sgrp)
11507                 sgrp->Add(vol->GetID());
11508             }
11509
11510           // --- modify the face
11511
11512           aFace->ChangeNodes(&ln[0], ln.size());
11513         }
11514     }
11515   return true;
11516 }
11517
11518 //================================================================================
11519 /*!
11520  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11521  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11522  * \return TRUE if operation has been completed successfully, FALSE otherwise
11523  */
11524 //================================================================================
11525
11526 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11527 {
11528   // iterates on volume elements and detect all free faces on them
11529   SMESHDS_Mesh* aMesh = GetMeshDS();
11530   if (!aMesh)
11531     return false;
11532   //bool res = false;
11533   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11534   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11535   while(vIt->more())
11536   {
11537     const SMDS_MeshVolume* volume = vIt->next();
11538     SMDS_VolumeTool vTool( volume );
11539     vTool.SetExternalNormal();
11540     const bool isPoly = volume->IsPoly();
11541     const bool isQuad = volume->IsQuadratic();
11542     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11543     {
11544       if (!vTool.IsFreeFace(iface))
11545         continue;
11546       nbFree++;
11547       vector<const SMDS_MeshNode *> nodes;
11548       int nbFaceNodes = vTool.NbFaceNodes(iface);
11549       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11550       int inode = 0;
11551       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11552         nodes.push_back(faceNodes[inode]);
11553       if (isQuad)
11554         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11555           nodes.push_back(faceNodes[inode]);
11556
11557       // add new face based on volume nodes
11558       if (aMesh->FindFace( nodes ) ) {
11559         nbExisted++;
11560         continue; // face already exsist
11561       }
11562       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11563       nbCreated++;
11564     }
11565   }
11566   return ( nbFree==(nbExisted+nbCreated) );
11567 }
11568
11569 namespace
11570 {
11571   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11572   {
11573     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11574       return n;
11575     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11576   }
11577 }
11578 //================================================================================
11579 /*!
11580  * \brief Creates missing boundary elements
11581  *  \param elements - elements whose boundary is to be checked
11582  *  \param dimension - defines type of boundary elements to create
11583  *  \param group - a group to store created boundary elements in
11584  *  \param targetMesh - a mesh to store created boundary elements in
11585  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11586  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
11587  *                                boundary elements will be copied into the targetMesh
11588  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11589  *                                boundary elements will be added into the new group
11590  *  \param aroundElements - if true, elements will be created on boundary of given
11591  *                          elements else, on boundary of the whole mesh.
11592  * \return nb of added boundary elements
11593  */
11594 //================================================================================
11595
11596 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11597                                        Bnd_Dimension           dimension,
11598                                        SMESH_Group*            group/*=0*/,
11599                                        SMESH_Mesh*             targetMesh/*=0*/,
11600                                        bool                    toCopyElements/*=false*/,
11601                                        bool                    toCopyExistingBoundary/*=false*/,
11602                                        bool                    toAddExistingBondary/*= false*/,
11603                                        bool                    aroundElements/*= false*/)
11604 {
11605   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11606   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11607   // hope that all elements are of the same type, do not check them all
11608   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11609     throw SALOME_Exception(LOCALIZED("wrong element type"));
11610
11611   if ( !targetMesh )
11612     toCopyElements = toCopyExistingBoundary = false;
11613
11614   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11615   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11616   int nbAddedBnd = 0;
11617
11618   // editor adding present bnd elements and optionally holding elements to add to the group
11619   SMESH_MeshEditor* presentEditor;
11620   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11621   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11622
11623   SMDS_VolumeTool vTool;
11624   TIDSortedElemSet avoidSet;
11625   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11626   int inode;
11627
11628   typedef vector<const SMDS_MeshNode*> TConnectivity;
11629
11630   SMDS_ElemIteratorPtr eIt;
11631   if (elements.empty())
11632     eIt = aMesh->elementsIterator(elemType);
11633   else
11634     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11635
11636   while (eIt->more())
11637   {
11638     const SMDS_MeshElement* elem = eIt->next();
11639     const int iQuad = elem->IsQuadratic();
11640
11641     // ------------------------------------------------------------------------------------
11642     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11643     // ------------------------------------------------------------------------------------
11644     vector<const SMDS_MeshElement*> presentBndElems;
11645     vector<TConnectivity>           missingBndElems;
11646     TConnectivity nodes;
11647     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11648     {
11649       vTool.SetExternalNormal();
11650       const SMDS_MeshElement* otherVol = 0;
11651       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11652       {
11653         if ( !vTool.IsFreeFace(iface, &otherVol) &&
11654              ( !aroundElements || elements.count( otherVol )))
11655           continue;
11656         const int nbFaceNodes = vTool.NbFaceNodes(iface);
11657         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11658         if ( missType == SMDSAbs_Edge ) // boundary edges
11659         {
11660           nodes.resize( 2+iQuad );
11661           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11662           {
11663             for ( int j = 0; j < nodes.size(); ++j )
11664               nodes[j] =nn[i+j];
11665             if ( const SMDS_MeshElement* edge =
11666                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11667               presentBndElems.push_back( edge );
11668             else
11669               missingBndElems.push_back( nodes );
11670           }
11671         }
11672         else // boundary face
11673         {
11674           nodes.clear();
11675           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11676             nodes.push_back( nn[inode] );
11677           if (iQuad)
11678             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11679               nodes.push_back( nn[inode] );
11680
11681           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11682             presentBndElems.push_back( f );
11683           else
11684             missingBndElems.push_back( nodes );
11685
11686           if ( targetMesh != myMesh )
11687           {
11688             // add 1D elements on face boundary to be added to a new mesh
11689             const SMDS_MeshElement* edge;
11690             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11691             {
11692               if ( iQuad )
11693                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11694               else
11695                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11696               if ( edge && avoidSet.insert( edge ).second )
11697                 presentBndElems.push_back( edge );
11698             }
11699           }
11700         }
11701       }
11702     }
11703     else                     // elem is a face ------------------------------------------
11704     {
11705       avoidSet.clear(), avoidSet.insert( elem );
11706       int nbNodes = elem->NbCornerNodes();
11707       nodes.resize( 2 /*+ iQuad*/);
11708       for ( int i = 0; i < nbNodes; i++ )
11709       {
11710         nodes[0] = elem->GetNode(i);
11711         nodes[1] = elem->GetNode((i+1)%nbNodes);
11712         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11713           continue; // not free link
11714
11715         //if ( iQuad )
11716         //nodes[2] = elem->GetNode( i + nbNodes );
11717         if ( const SMDS_MeshElement* edge =
11718              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11719           presentBndElems.push_back( edge );
11720         else
11721           missingBndElems.push_back( nodes );
11722       }
11723     }
11724
11725     // ---------------------------------
11726     // 2. Add missing boundary elements
11727     // ---------------------------------
11728     if ( targetMesh != myMesh )
11729       // instead of making a map of nodes in this mesh and targetMesh,
11730       // we create nodes with same IDs.
11731       for ( int i = 0; i < missingBndElems.size(); ++i )
11732       {
11733         TConnectivity& srcNodes = missingBndElems[i];
11734         TConnectivity  nodes( srcNodes.size() );
11735         for ( inode = 0; inode < nodes.size(); ++inode )
11736           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11737         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11738                                                                    missType,
11739                                                                    /*noMedium=*/true))
11740           continue;
11741         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11742         ++nbAddedBnd;
11743       }
11744     else
11745       for ( int i = 0; i < missingBndElems.size(); ++i )
11746       {
11747         TConnectivity& nodes = missingBndElems[i];
11748         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11749                                                                    missType,
11750                                                                    /*noMedium=*/true))
11751           continue;
11752         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11753         ++nbAddedBnd;
11754       }
11755
11756     // ----------------------------------
11757     // 3. Copy present boundary elements
11758     // ----------------------------------
11759     if ( toCopyExistingBoundary )
11760       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11761       {
11762         const SMDS_MeshElement* e = presentBndElems[i];
11763         TConnectivity nodes( e->NbNodes() );
11764         for ( inode = 0; inode < nodes.size(); ++inode )
11765           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11766         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11767       }
11768     else // store present elements to add them to a group
11769       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11770       {
11771         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11772       }
11773       
11774   } // loop on given elements
11775
11776   // ---------------------------------------------
11777   // 4. Fill group with boundary elements
11778   // ---------------------------------------------
11779   if ( group )
11780   {
11781     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11782       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11783         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11784   }
11785   tgtEditor.myLastCreatedElems.Clear();
11786   tgtEditor2.myLastCreatedElems.Clear();
11787
11788   // -----------------------
11789   // 5. Copy given elements
11790   // -----------------------
11791   if ( toCopyElements && targetMesh != myMesh )
11792   {
11793     if (elements.empty())
11794       eIt = aMesh->elementsIterator(elemType);
11795     else
11796       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11797     while (eIt->more())
11798     {
11799       const SMDS_MeshElement* elem = eIt->next();
11800       TConnectivity nodes( elem->NbNodes() );
11801       for ( inode = 0; inode < nodes.size(); ++inode )
11802         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11803       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11804
11805       tgtEditor.myLastCreatedElems.Clear();
11806     }
11807   }
11808   return nbAddedBnd;
11809 }