]> SALOME platform Git repositories - modules/smesh.git/blob - src/SMESH/SMESH_MeshEditor.cxx
Salome HOME
feb44971c0d8456157f218530d96df4bf5c928eb
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 // Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27 //
28 #define CHRONODEF
29 #include "SMESH_MeshEditor.hxx"
30
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
42
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
45
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
52
53 #include "utilities.h"
54
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
58 #include <ElCLib.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
74 #include <TopExp.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
79 #include <TopoDS.hxx>
80 #include <TopoDS_Face.hxx>
81 #include <gp.hxx>
82 #include <gp_Ax1.hxx>
83 #include <gp_Dir.hxx>
84 #include <gp_Lin.hxx>
85 #include <gp_Pln.hxx>
86 #include <gp_Trsf.hxx>
87 #include <gp_Vec.hxx>
88 #include <gp_XY.hxx>
89 #include <gp_XYZ.hxx>
90
91 #include <math.h>
92
93 #include <map>
94 #include <set>
95 #include <numeric>
96 #include <limits>
97 #include <algorithm>
98 #include <sstream>
99
100 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
101
102 using namespace std;
103 using namespace SMESH::Controls;
104
105 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
106 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
107
108 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
109
110 //=======================================================================
111 //function : SMESH_MeshEditor
112 //purpose  :
113 //=======================================================================
114
115 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
116   :myMesh( theMesh ) // theMesh may be NULL
117 {
118 }
119
120 //=======================================================================
121 /*!
122  * \brief Add element
123  */
124 //=======================================================================
125
126 SMDS_MeshElement*
127 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
128                              const SMDSAbs_ElementType            type,
129                              const bool                           isPoly,
130                              const int                            ID)
131 {
132   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
133   SMDS_MeshElement* e = 0;
134   int nbnode = node.size();
135   SMESHDS_Mesh* mesh = GetMeshDS();
136   switch ( type ) {
137   case SMDSAbs_Face:
138     if ( !isPoly ) {
139       if      (nbnode == 3) {
140         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
141         else           e = mesh->AddFace      (node[0], node[1], node[2] );
142       }
143       else if (nbnode == 4) {
144         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
145         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
146       }
147       else if (nbnode == 6) {
148         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
149                                                node[4], node[5], ID);
150         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
151                                                node[4], node[5] );
152       }
153       else if (nbnode == 8) {
154         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
155                                                node[4], node[5], node[6], node[7], ID);
156         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
157                                                node[4], node[5], node[6], node[7] );
158       }
159     } else {
160       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
161       else           e = mesh->AddPolygonalFace      (node    );
162     }
163     break;
164
165   case SMDSAbs_Volume:
166     if ( !isPoly ) {
167       if      (nbnode == 4) {
168         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
169         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
170       }
171       else if (nbnode == 5) {
172         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
173                                                  node[4], ID);
174         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
175                                                  node[4] );
176       }
177       else if (nbnode == 6) {
178         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
179                                                  node[4], node[5], ID);
180         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
181                                                  node[4], node[5] );
182       }
183       else if (nbnode == 8) {
184         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185                                                  node[4], node[5], node[6], node[7], ID);
186         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
187                                                  node[4], node[5], node[6], node[7] );
188       }
189       else if (nbnode == 10) {
190         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
191                                                  node[4], node[5], node[6], node[7],
192                                                  node[8], node[9], ID);
193         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
194                                                  node[4], node[5], node[6], node[7],
195                                                  node[8], node[9] );
196       }
197       else if (nbnode == 13) {
198         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
199                                                  node[4], node[5], node[6], node[7],
200                                                  node[8], node[9], node[10],node[11],
201                                                  node[12],ID);
202         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
203                                                  node[4], node[5], node[6], node[7],
204                                                  node[8], node[9], node[10],node[11],
205                                                  node[12] );
206       }
207       else if (nbnode == 15) {
208         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
209                                                  node[4], node[5], node[6], node[7],
210                                                  node[8], node[9], node[10],node[11],
211                                                  node[12],node[13],node[14],ID);
212         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
213                                                  node[4], node[5], node[6], node[7],
214                                                  node[8], node[9], node[10],node[11],
215                                                  node[12],node[13],node[14] );
216       }
217       else if (nbnode == 20) {
218         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
219                                                  node[4], node[5], node[6], node[7],
220                                                  node[8], node[9], node[10],node[11],
221                                                  node[12],node[13],node[14],node[15],
222                                                  node[16],node[17],node[18],node[19],ID);
223         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
224                                                  node[4], node[5], node[6], node[7],
225                                                  node[8], node[9], node[10],node[11],
226                                                  node[12],node[13],node[14],node[15],
227                                                  node[16],node[17],node[18],node[19] );
228       }
229     }
230     break;
231
232   case SMDSAbs_Edge:
233     if ( nbnode == 2 ) {
234       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
235       else           e = mesh->AddEdge      (node[0], node[1] );
236     }
237     else if ( nbnode == 3 ) {
238       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
239       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
240     }
241     break;
242
243   case SMDSAbs_0DElement:
244     if ( nbnode == 1 ) {
245       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
246       else           e = mesh->Add0DElement      (node[0] );
247     }
248     break;
249
250   case SMDSAbs_Node:
251     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
252     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
253     break;
254
255   default:;
256   }
257   if ( e ) myLastCreatedElems.Append( e );
258   return e;
259 }
260
261 //=======================================================================
262 /*!
263  * \brief Add element
264  */
265 //=======================================================================
266
267 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
268                                                const SMDSAbs_ElementType type,
269                                                const bool                isPoly,
270                                                const int                 ID)
271 {
272   vector<const SMDS_MeshNode*> nodes;
273   nodes.reserve( nodeIDs.size() );
274   vector<int>::const_iterator id = nodeIDs.begin();
275   while ( id != nodeIDs.end() ) {
276     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
277       nodes.push_back( node );
278     else
279       return 0;
280   }
281   return AddElement( nodes, type, isPoly, ID );
282 }
283
284 //=======================================================================
285 //function : Remove
286 //purpose  : Remove a node or an element.
287 //           Modify a compute state of sub-meshes which become empty
288 //=======================================================================
289
290 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
291                               const bool         isNodes )
292 {
293   myLastCreatedElems.Clear();
294   myLastCreatedNodes.Clear();
295
296   SMESHDS_Mesh* aMesh = GetMeshDS();
297   set< SMESH_subMesh *> smmap;
298
299   int removed = 0;
300   list<int>::const_iterator it = theIDs.begin();
301   for ( ; it != theIDs.end(); it++ ) {
302     const SMDS_MeshElement * elem;
303     if ( isNodes )
304       elem = aMesh->FindNode( *it );
305     else
306       elem = aMesh->FindElement( *it );
307     if ( !elem )
308       continue;
309
310     // Notify VERTEX sub-meshes about modification
311     if ( isNodes ) {
312       const SMDS_MeshNode* node = cast2Node( elem );
313       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
314         if ( int aShapeID = node->getshapeId() )
315           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
316             smmap.insert( sm );
317     }
318     // Find sub-meshes to notify about modification
319     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
320     //     while ( nodeIt->more() ) {
321     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
322     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
323     //       if ( aPosition.get() ) {
324     //         if ( int aShapeID = aPosition->GetShapeId() ) {
325     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
326     //             smmap.insert( sm );
327     //         }
328     //       }
329     //     }
330
331     // Do remove
332     if ( isNodes )
333       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
334     else
335       aMesh->RemoveElement( elem );
336     removed++;
337   }
338
339   // Notify sub-meshes about modification
340   if ( !smmap.empty() ) {
341     set< SMESH_subMesh *>::iterator smIt;
342     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
343       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
344   }
345
346   //   // Check if the whole mesh becomes empty
347   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
348   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
349
350   return removed;
351 }
352
353 //=======================================================================
354 //function : FindShape
355 //purpose  : Return an index of the shape theElem is on
356 //           or zero if a shape not found
357 //=======================================================================
358
359 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
360 {
361   myLastCreatedElems.Clear();
362   myLastCreatedNodes.Clear();
363
364   SMESHDS_Mesh * aMesh = GetMeshDS();
365   if ( aMesh->ShapeToMesh().IsNull() )
366     return 0;
367
368   int aShapeID = theElem->getshapeId();
369   if ( aShapeID < 1 )
370     return 0;
371
372   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
373     if ( sm->Contains( theElem ))
374       return aShapeID;
375
376   if ( theElem->GetType() == SMDSAbs_Node ) {
377     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
378   }
379   else {
380     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
381   }
382
383   TopoDS_Shape aShape; // the shape a node of theElem is on
384   if ( theElem->GetType() != SMDSAbs_Node )
385   {
386     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
387     while ( nodeIt->more() ) {
388       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
389       if ((aShapeID = node->getshapeId()) > 0) {
390         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
391           if ( sm->Contains( theElem ))
392             return aShapeID;
393           if ( aShape.IsNull() )
394             aShape = aMesh->IndexToShape( aShapeID );
395         }
396       }
397     }
398   }
399
400   // None of nodes is on a proper shape,
401   // find the shape among ancestors of aShape on which a node is
402   if ( !aShape.IsNull() ) {
403     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
404     for ( ; ancIt.More(); ancIt.Next() ) {
405       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
406       if ( sm && sm->Contains( theElem ))
407         return aMesh->ShapeToIndex( ancIt.Value() );
408     }
409   }
410   else
411   {
412     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
413     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
414     for ( ; id_sm != id2sm.end(); ++id_sm )
415       if ( id_sm->second->Contains( theElem ))
416         return id_sm->first;
417   }
418
419   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
420   return 0;
421 }
422
423 //=======================================================================
424 //function : IsMedium
425 //purpose  :
426 //=======================================================================
427
428 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
429                                 const SMDSAbs_ElementType typeToCheck)
430 {
431   bool isMedium = false;
432   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
433   while (it->more() && !isMedium ) {
434     const SMDS_MeshElement* elem = it->next();
435     isMedium = elem->IsMediumNode(node);
436   }
437   return isMedium;
438 }
439
440 //=======================================================================
441 //function : ShiftNodesQuadTria
442 //purpose  : auxilary
443 //           Shift nodes in the array corresponded to quadratic triangle
444 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
445 //=======================================================================
446 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
447 {
448   const SMDS_MeshNode* nd1 = aNodes[0];
449   aNodes[0] = aNodes[1];
450   aNodes[1] = aNodes[2];
451   aNodes[2] = nd1;
452   const SMDS_MeshNode* nd2 = aNodes[3];
453   aNodes[3] = aNodes[4];
454   aNodes[4] = aNodes[5];
455   aNodes[5] = nd2;
456 }
457
458 //=======================================================================
459 //function : GetNodesFromTwoTria
460 //purpose  : auxilary
461 //           Shift nodes in the array corresponded to quadratic triangle
462 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
463 //=======================================================================
464 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
465                                 const SMDS_MeshElement * theTria2,
466                                 const SMDS_MeshNode* N1[],
467                                 const SMDS_MeshNode* N2[])
468 {
469   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
470   int i=0;
471   while(i<6) {
472     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
473     i++;
474   }
475   if(it->more()) return false;
476   it = theTria2->nodesIterator();
477   i=0;
478   while(i<6) {
479     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
480     i++;
481   }
482   if(it->more()) return false;
483
484   int sames[3] = {-1,-1,-1};
485   int nbsames = 0;
486   int j;
487   for(i=0; i<3; i++) {
488     for(j=0; j<3; j++) {
489       if(N1[i]==N2[j]) {
490         sames[i] = j;
491         nbsames++;
492         break;
493       }
494     }
495   }
496   if(nbsames!=2) return false;
497   if(sames[0]>-1) {
498     ShiftNodesQuadTria(N1);
499     if(sames[1]>-1) {
500       ShiftNodesQuadTria(N1);
501     }
502   }
503   i = sames[0] + sames[1] + sames[2];
504   for(; i<2; i++) {
505     ShiftNodesQuadTria(N2);
506   }
507   // now we receive following N1 and N2 (using numeration as above image)
508   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
509   // i.e. first nodes from both arrays determ new diagonal
510   return true;
511 }
512
513 //=======================================================================
514 //function : InverseDiag
515 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
516 //           but having other common link.
517 //           Return False if args are improper
518 //=======================================================================
519
520 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
521                                     const SMDS_MeshElement * theTria2 )
522 {
523   MESSAGE("InverseDiag");
524   myLastCreatedElems.Clear();
525   myLastCreatedNodes.Clear();
526
527   if (!theTria1 || !theTria2)
528     return false;
529
530   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
531   if (!F1) return false;
532   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
533   if (!F2) return false;
534   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
535       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
536
537     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
538     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
539     //    |/ |                                         | \|
540     //  B +--+ 2                                     B +--+ 2
541
542     // put nodes in array and find out indices of the same ones
543     const SMDS_MeshNode* aNodes [6];
544     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
545     int i = 0;
546     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
547     while ( it->more() ) {
548       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
549
550       if ( i > 2 ) // theTria2
551         // find same node of theTria1
552         for ( int j = 0; j < 3; j++ )
553           if ( aNodes[ i ] == aNodes[ j ]) {
554             sameInd[ j ] = i;
555             sameInd[ i ] = j;
556             break;
557           }
558       // next
559       i++;
560       if ( i == 3 ) {
561         if ( it->more() )
562           return false; // theTria1 is not a triangle
563         it = theTria2->nodesIterator();
564       }
565       if ( i == 6 && it->more() )
566         return false; // theTria2 is not a triangle
567     }
568
569     // find indices of 1,2 and of A,B in theTria1
570     int iA = 0, iB = 0, i1 = 0, i2 = 0;
571     for ( i = 0; i < 6; i++ ) {
572       if ( sameInd [ i ] == 0 ) {
573         if ( i < 3 ) i1 = i;
574         else         i2 = i;
575       }
576       else if (i < 3) {
577         if ( iA ) iB = i;
578         else      iA = i;
579       }
580     }
581     // nodes 1 and 2 should not be the same
582     if ( aNodes[ i1 ] == aNodes[ i2 ] )
583       return false;
584
585     // theTria1: A->2
586     aNodes[ iA ] = aNodes[ i2 ];
587     // theTria2: B->1
588     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
589
590     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
591     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
592
593     return true;
594
595   } // end if(F1 && F2)
596
597   // check case of quadratic faces
598   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
599     return false;
600   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
601     return false;
602
603   //       5
604   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
605   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
606   //    |   / |
607   //  7 +  +  + 6
608   //    | /9  |
609   //    |/    |
610   //  4 +--+--+ 3
611   //       8
612
613   const SMDS_MeshNode* N1 [6];
614   const SMDS_MeshNode* N2 [6];
615   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
616     return false;
617   // now we receive following N1 and N2 (using numeration as above image)
618   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
619   // i.e. first nodes from both arrays determ new diagonal
620
621   const SMDS_MeshNode* N1new [6];
622   const SMDS_MeshNode* N2new [6];
623   N1new[0] = N1[0];
624   N1new[1] = N2[0];
625   N1new[2] = N2[1];
626   N1new[3] = N1[4];
627   N1new[4] = N2[3];
628   N1new[5] = N1[5];
629   N2new[0] = N1[0];
630   N2new[1] = N1[1];
631   N2new[2] = N2[0];
632   N2new[3] = N1[3];
633   N2new[4] = N2[5];
634   N2new[5] = N1[4];
635   // replaces nodes in faces
636   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
637   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
638
639   return true;
640 }
641
642 //=======================================================================
643 //function : findTriangles
644 //purpose  : find triangles sharing theNode1-theNode2 link
645 //=======================================================================
646
647 static bool findTriangles(const SMDS_MeshNode *    theNode1,
648                           const SMDS_MeshNode *    theNode2,
649                           const SMDS_MeshElement*& theTria1,
650                           const SMDS_MeshElement*& theTria2)
651 {
652   if ( !theNode1 || !theNode2 ) return false;
653
654   theTria1 = theTria2 = 0;
655
656   set< const SMDS_MeshElement* > emap;
657   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
658   while (it->more()) {
659     const SMDS_MeshElement* elem = it->next();
660     if ( elem->NbNodes() == 3 )
661       emap.insert( elem );
662   }
663   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
664   while (it->more()) {
665     const SMDS_MeshElement* elem = it->next();
666     if ( emap.find( elem ) != emap.end() ) {
667       if ( theTria1 ) {
668         // theTria1 must be element with minimum ID
669         if( theTria1->GetID() < elem->GetID() ) {
670           theTria2 = elem;
671         }
672         else {
673           theTria2 = theTria1;
674           theTria1 = elem;
675         }
676         break;
677       }
678       else {
679         theTria1 = elem;
680       }
681     }
682   }
683   return ( theTria1 && theTria2 );
684 }
685
686 //=======================================================================
687 //function : InverseDiag
688 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
689 //           with ones built on the same 4 nodes but having other common link.
690 //           Return false if proper faces not found
691 //=======================================================================
692
693 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
694                                     const SMDS_MeshNode * theNode2)
695 {
696   myLastCreatedElems.Clear();
697   myLastCreatedNodes.Clear();
698
699   MESSAGE( "::InverseDiag()" );
700
701   const SMDS_MeshElement *tr1, *tr2;
702   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
703     return false;
704
705   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
706   if (!F1) return false;
707   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
708   if (!F2) return false;
709   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
710       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
711
712     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
713     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
714     //    |/ |                                    | \|
715     //  B +--+ 2                                B +--+ 2
716
717     // put nodes in array
718     // and find indices of 1,2 and of A in tr1 and of B in tr2
719     int i, iA1 = 0, i1 = 0;
720     const SMDS_MeshNode* aNodes1 [3];
721     SMDS_ElemIteratorPtr it;
722     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
723       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
724       if ( aNodes1[ i ] == theNode1 )
725         iA1 = i; // node A in tr1
726       else if ( aNodes1[ i ] != theNode2 )
727         i1 = i;  // node 1
728     }
729     int iB2 = 0, i2 = 0;
730     const SMDS_MeshNode* aNodes2 [3];
731     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
732       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
733       if ( aNodes2[ i ] == theNode2 )
734         iB2 = i; // node B in tr2
735       else if ( aNodes2[ i ] != theNode1 )
736         i2 = i;  // node 2
737     }
738
739     // nodes 1 and 2 should not be the same
740     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
741       return false;
742
743     // tr1: A->2
744     aNodes1[ iA1 ] = aNodes2[ i2 ];
745     // tr2: B->1
746     aNodes2[ iB2 ] = aNodes1[ i1 ];
747
748     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
749     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
750
751     return true;
752   }
753
754   // check case of quadratic faces
755   return InverseDiag(tr1,tr2);
756 }
757
758 //=======================================================================
759 //function : getQuadrangleNodes
760 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
761 //           fusion of triangles tr1 and tr2 having shared link on
762 //           theNode1 and theNode2
763 //=======================================================================
764
765 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
766                         const SMDS_MeshNode *    theNode1,
767                         const SMDS_MeshNode *    theNode2,
768                         const SMDS_MeshElement * tr1,
769                         const SMDS_MeshElement * tr2 )
770 {
771   if( tr1->NbNodes() != tr2->NbNodes() )
772     return false;
773   // find the 4-th node to insert into tr1
774   const SMDS_MeshNode* n4 = 0;
775   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
776   int i=0;
777   while ( !n4 && i<3 ) {
778     const SMDS_MeshNode * n = cast2Node( it->next() );
779     i++;
780     bool isDiag = ( n == theNode1 || n == theNode2 );
781     if ( !isDiag )
782       n4 = n;
783   }
784   // Make an array of nodes to be in a quadrangle
785   int iNode = 0, iFirstDiag = -1;
786   it = tr1->nodesIterator();
787   i=0;
788   while ( i<3 ) {
789     const SMDS_MeshNode * n = cast2Node( it->next() );
790     i++;
791     bool isDiag = ( n == theNode1 || n == theNode2 );
792     if ( isDiag ) {
793       if ( iFirstDiag < 0 )
794         iFirstDiag = iNode;
795       else if ( iNode - iFirstDiag == 1 )
796         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
797     }
798     else if ( n == n4 ) {
799       return false; // tr1 and tr2 should not have all the same nodes
800     }
801     theQuadNodes[ iNode++ ] = n;
802   }
803   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
804     theQuadNodes[ iNode ] = n4;
805
806   return true;
807 }
808
809 //=======================================================================
810 //function : DeleteDiag
811 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
812 //           with a quadrangle built on the same 4 nodes.
813 //           Return false if proper faces not found
814 //=======================================================================
815
816 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
817                                    const SMDS_MeshNode * theNode2)
818 {
819   myLastCreatedElems.Clear();
820   myLastCreatedNodes.Clear();
821
822   MESSAGE( "::DeleteDiag()" );
823
824   const SMDS_MeshElement *tr1, *tr2;
825   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
826     return false;
827
828   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
829   if (!F1) return false;
830   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
831   if (!F2) return false;
832   SMESHDS_Mesh * aMesh = GetMeshDS();
833
834   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
835       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
836
837     const SMDS_MeshNode* aNodes [ 4 ];
838     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
839       return false;
840
841     const SMDS_MeshElement* newElem = 0;
842     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
843     myLastCreatedElems.Append(newElem);
844     AddToSameGroups( newElem, tr1, aMesh );
845     int aShapeId = tr1->getshapeId();
846     if ( aShapeId )
847       {
848         aMesh->SetMeshElementOnShape( newElem, aShapeId );
849       }
850     aMesh->RemoveElement( tr1 );
851     aMesh->RemoveElement( tr2 );
852
853     return true;
854   }
855
856   // check case of quadratic faces
857   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
858     return false;
859   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
860     return false;
861
862   //       5
863   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
864   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
865   //    |   / |
866   //  7 +  +  + 6
867   //    | /9  |
868   //    |/    |
869   //  4 +--+--+ 3
870   //       8
871
872   const SMDS_MeshNode* N1 [6];
873   const SMDS_MeshNode* N2 [6];
874   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
875     return false;
876   // now we receive following N1 and N2 (using numeration as above image)
877   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
878   // i.e. first nodes from both arrays determ new diagonal
879
880   const SMDS_MeshNode* aNodes[8];
881   aNodes[0] = N1[0];
882   aNodes[1] = N1[1];
883   aNodes[2] = N2[0];
884   aNodes[3] = N2[1];
885   aNodes[4] = N1[3];
886   aNodes[5] = N2[5];
887   aNodes[6] = N2[3];
888   aNodes[7] = N1[5];
889
890   const SMDS_MeshElement* newElem = 0;
891   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
892                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
893   myLastCreatedElems.Append(newElem);
894   AddToSameGroups( newElem, tr1, aMesh );
895   int aShapeId = tr1->getshapeId();
896   if ( aShapeId )
897     {
898       aMesh->SetMeshElementOnShape( newElem, aShapeId );
899     }
900   aMesh->RemoveElement( tr1 );
901   aMesh->RemoveElement( tr2 );
902
903   // remove middle node (9)
904   GetMeshDS()->RemoveNode( N1[4] );
905
906   return true;
907 }
908
909 //=======================================================================
910 //function : Reorient
911 //purpose  : Reverse theElement orientation
912 //=======================================================================
913
914 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
915 {
916   MESSAGE("Reorient");
917   myLastCreatedElems.Clear();
918   myLastCreatedNodes.Clear();
919
920   if (!theElem)
921     return false;
922   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
923   if ( !it || !it->more() )
924     return false;
925
926   switch ( theElem->GetType() ) {
927
928   case SMDSAbs_Edge:
929   case SMDSAbs_Face: {
930     if(!theElem->IsQuadratic()) {
931       int i = theElem->NbNodes();
932       vector<const SMDS_MeshNode*> aNodes( i );
933       while ( it->more() )
934         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
935       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
936     }
937     else {
938       // quadratic elements
939       if(theElem->GetType()==SMDSAbs_Edge) {
940         vector<const SMDS_MeshNode*> aNodes(3);
941         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
942         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
943         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
944         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
945       }
946       else {
947         int nbn = theElem->NbNodes();
948         vector<const SMDS_MeshNode*> aNodes(nbn);
949         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
950         int i=1;
951         for(; i<nbn/2; i++) {
952           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
953         }
954         for(i=0; i<nbn/2; i++) {
955           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
956         }
957         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
958       }
959     }
960   }
961   case SMDSAbs_Volume: {
962     if (theElem->IsPoly()) {
963       // TODO reorient vtk polyhedron
964       MESSAGE("reorient vtk polyhedron ?");
965       const SMDS_VtkVolume* aPolyedre =
966         dynamic_cast<const SMDS_VtkVolume*>( theElem );
967       if (!aPolyedre) {
968         MESSAGE("Warning: bad volumic element");
969         return false;
970       }
971
972       int nbFaces = aPolyedre->NbFaces();
973       vector<const SMDS_MeshNode *> poly_nodes;
974       vector<int> quantities (nbFaces);
975
976       // reverse each face of the polyedre
977       for (int iface = 1; iface <= nbFaces; iface++) {
978         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
979         quantities[iface - 1] = nbFaceNodes;
980
981         for (inode = nbFaceNodes; inode >= 1; inode--) {
982           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
983           poly_nodes.push_back(curNode);
984         }
985       }
986
987       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
988
989     }
990     else {
991       SMDS_VolumeTool vTool;
992       if ( !vTool.Set( theElem ))
993         return false;
994       vTool.Inverse();
995       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
996       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
997     }
998   }
999   default:;
1000   }
1001
1002   return false;
1003 }
1004
1005 //=======================================================================
1006 //function : getBadRate
1007 //purpose  :
1008 //=======================================================================
1009
1010 static double getBadRate (const SMDS_MeshElement*               theElem,
1011                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1012 {
1013   SMESH::Controls::TSequenceOfXYZ P;
1014   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1015     return 1e100;
1016   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1017   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1018 }
1019
1020 //=======================================================================
1021 //function : QuadToTri
1022 //purpose  : Cut quadrangles into triangles.
1023 //           theCrit is used to select a diagonal to cut
1024 //=======================================================================
1025
1026 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1027                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1028 {
1029   myLastCreatedElems.Clear();
1030   myLastCreatedNodes.Clear();
1031
1032   MESSAGE( "::QuadToTri()" );
1033
1034   if ( !theCrit.get() )
1035     return false;
1036
1037   SMESHDS_Mesh * aMesh = GetMeshDS();
1038
1039   Handle(Geom_Surface) surface;
1040   SMESH_MesherHelper   helper( *GetMesh() );
1041
1042   TIDSortedElemSet::iterator itElem;
1043   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1044     const SMDS_MeshElement* elem = *itElem;
1045     if ( !elem || elem->GetType() != SMDSAbs_Face )
1046       continue;
1047     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1048       continue;
1049
1050     // retrieve element nodes
1051     const SMDS_MeshNode* aNodes [8];
1052     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1053     int i = 0;
1054     while ( itN->more() )
1055       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1056
1057     // compare two sets of possible triangles
1058     double aBadRate1, aBadRate2; // to what extent a set is bad
1059     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1060     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1061     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1062
1063     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1064     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1065     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1066
1067     int aShapeId = FindShape( elem );
1068     const SMDS_MeshElement* newElem1 = 0;
1069     const SMDS_MeshElement* newElem2 = 0;
1070
1071     if( !elem->IsQuadratic() ) {
1072
1073       // split liner quadrangle
1074       if ( aBadRate1 <= aBadRate2 ) {
1075         // tr1 + tr2 is better
1076         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1077         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1078       }
1079       else {
1080         // tr3 + tr4 is better
1081         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1082         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1083       }
1084     }
1085     else {
1086
1087       // split quadratic quadrangle
1088
1089       // get surface elem is on
1090       if ( aShapeId != helper.GetSubShapeID() ) {
1091         surface.Nullify();
1092         TopoDS_Shape shape;
1093         if ( aShapeId > 0 )
1094           shape = aMesh->IndexToShape( aShapeId );
1095         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1096           TopoDS_Face face = TopoDS::Face( shape );
1097           surface = BRep_Tool::Surface( face );
1098           if ( !surface.IsNull() )
1099             helper.SetSubShape( shape );
1100         }
1101       }
1102       // get elem nodes
1103       const SMDS_MeshNode* aNodes [8];
1104       const SMDS_MeshNode* inFaceNode = 0;
1105       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1106       int i = 0;
1107       while ( itN->more() ) {
1108         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1109         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1110              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1111         {
1112           inFaceNode = aNodes[ i-1 ];
1113         }
1114       }
1115       // find middle point for (0,1,2,3)
1116       // and create a node in this point;
1117       gp_XYZ p( 0,0,0 );
1118       if ( surface.IsNull() ) {
1119         for(i=0; i<4; i++)
1120           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1121         p /= 4;
1122       }
1123       else {
1124         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1125         gp_XY uv( 0,0 );
1126         for(i=0; i<4; i++)
1127           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1128         uv /= 4.;
1129         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1130       }
1131       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1132       myLastCreatedNodes.Append(newN);
1133
1134       // create a new element
1135       if ( aBadRate1 <= aBadRate2 ) {
1136         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1137                                   aNodes[6], aNodes[7], newN );
1138         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1139                                   newN,      aNodes[4], aNodes[5] );
1140       }
1141       else {
1142         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1143                                   aNodes[7], aNodes[4], newN );
1144         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1145                                   newN,      aNodes[5], aNodes[6] );
1146       }
1147     } // quadratic case
1148
1149     // care of a new element
1150
1151     myLastCreatedElems.Append(newElem1);
1152     myLastCreatedElems.Append(newElem2);
1153     AddToSameGroups( newElem1, elem, aMesh );
1154     AddToSameGroups( newElem2, elem, aMesh );
1155
1156     // put a new triangle on the same shape
1157     if ( aShapeId )
1158       {
1159         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1160         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1161       }
1162     aMesh->RemoveElement( elem );
1163   }
1164   return true;
1165 }
1166
1167 //=======================================================================
1168 //function : BestSplit
1169 //purpose  : Find better diagonal for cutting.
1170 //=======================================================================
1171
1172 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1173                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1174 {
1175   myLastCreatedElems.Clear();
1176   myLastCreatedNodes.Clear();
1177
1178   if (!theCrit.get())
1179     return -1;
1180
1181   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1182     return -1;
1183
1184   if( theQuad->NbNodes()==4 ||
1185       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1186
1187     // retrieve element nodes
1188     const SMDS_MeshNode* aNodes [4];
1189     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1190     int i = 0;
1191     //while (itN->more())
1192     while (i<4) {
1193       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1194     }
1195     // compare two sets of possible triangles
1196     double aBadRate1, aBadRate2; // to what extent a set is bad
1197     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1198     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1199     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1200
1201     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1202     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1203     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1204
1205     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1206       return 1; // diagonal 1-3
1207
1208     return 2; // diagonal 2-4
1209   }
1210   return -1;
1211 }
1212
1213 namespace
1214 {
1215   // Methods of splitting volumes into tetra
1216
1217   const int theHexTo5_1[5*4+1] =
1218     {
1219       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1220     };
1221   const int theHexTo5_2[5*4+1] =
1222     {
1223       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1224     };
1225   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1226
1227   const int theHexTo6_1[6*4+1] =
1228     {
1229       1, 5, 6, 0,    0, 1, 2, 6,     0, 4, 5, 6,    0, 4, 6, 7,     0, 2, 3, 6,   0, 3, 7, 6,  -1
1230     };
1231   const int theHexTo6_2[6*4+1] =
1232     {
1233       2, 6, 7, 1,    1, 2, 3, 7,     1, 5, 6, 7,    1, 5, 7, 4,     1, 3, 0, 7,   1, 0, 4, 7,  -1
1234     };
1235   const int theHexTo6_3[6*4+1] =
1236     {
1237       3, 7, 4, 2,    2, 3, 0, 4,     2, 6, 7, 4,    2, 6, 4, 5,     2, 0, 1, 4,   2, 1, 5, 4,  -1
1238     };
1239   const int theHexTo6_4[6*4+1] =
1240     {
1241       0, 4, 5, 3,    3, 0, 1, 5,     3, 7, 4, 5,    3, 7, 5, 6,     3, 1, 2, 5,   3, 2, 6, 5,  -1
1242     };
1243   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1244
1245   const int thePyraTo2_1[2*4+1] =
1246     {
1247       0, 1, 2, 4,    0, 2, 3, 4,   -1
1248     };
1249   const int thePyraTo2_2[2*4+1] =
1250     {
1251       1, 2, 3, 4,    1, 3, 0, 4,   -1
1252     };
1253   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1254
1255   const int thePentaTo3_1[3*4+1] =
1256     {
1257       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1258     };
1259   const int thePentaTo3_2[3*4+1] =
1260     {
1261       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1262     };
1263   const int thePentaTo3_3[3*4+1] =
1264     {
1265       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1266     };
1267   const int thePentaTo3_4[3*4+1] =
1268     {
1269       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1270     };
1271   const int thePentaTo3_5[3*4+1] =
1272     {
1273       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1274     };
1275   const int thePentaTo3_6[3*4+1] =
1276     {
1277       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1278     };
1279   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1280                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1281
1282   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1283   {
1284     int _n1, _n2, _n3;
1285     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1286     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1287     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1288   };
1289   struct TSplitMethod
1290   {
1291     int        _nbTetra;
1292     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1293     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1294     bool       _ownConn;      //!< to delete _connectivity in destructor
1295     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1296
1297     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1298       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1299     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1300     bool hasFacet( const TTriangleFacet& facet ) const
1301     {
1302       const int* tetConn = _connectivity;
1303       for ( ; tetConn[0] >= 0; tetConn += 4 )
1304         if (( facet.contains( tetConn[0] ) +
1305               facet.contains( tetConn[1] ) +
1306               facet.contains( tetConn[2] ) +
1307               facet.contains( tetConn[3] )) == 3 )
1308           return true;
1309       return false;
1310     }
1311   };
1312
1313   //=======================================================================
1314   /*!
1315    * \brief return TSplitMethod for the given element
1316    */
1317   //=======================================================================
1318
1319   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1320   {
1321     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1322
1323     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1324     // an edge and a face barycenter; tertaherdons are based on triangles and
1325     // a volume barycenter
1326     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1327
1328     // Find out how adjacent volumes are split
1329
1330     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1331     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1332     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1333     {
1334       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1335       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1336       if ( nbNodes < 4 ) continue;
1337
1338       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1339       const int* nInd = vol.GetFaceNodesIndices( iF );
1340       if ( nbNodes == 4 )
1341       {
1342         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1343         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1344         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1345         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1346       }
1347       else
1348       {
1349         int iCom = 0; // common node of triangle faces to split into
1350         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1351         {
1352           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1353                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1354                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1355           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1356                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1357                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1358           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1359           {
1360             triaSplits.push_back( t012 );
1361             triaSplits.push_back( t023 );
1362             break;
1363           }
1364         }
1365       }
1366       if ( !triaSplits.empty() )
1367         hasAdjacentSplits = true;
1368     }
1369
1370     // Among variants of split method select one compliant with adjacent volumes
1371
1372     TSplitMethod method;
1373     if ( !vol.Element()->IsPoly() && !is24TetMode )
1374     {
1375       int nbVariants = 2, nbTet = 0;
1376       const int** connVariants = 0;
1377       switch ( vol.Element()->GetEntityType() )
1378       {
1379       case SMDSEntity_Hexa:
1380       case SMDSEntity_Quad_Hexa:
1381         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1382           connVariants = theHexTo5, nbTet = 5;
1383         else
1384           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1385         break;
1386       case SMDSEntity_Pyramid:
1387       case SMDSEntity_Quad_Pyramid:
1388         connVariants = thePyraTo2;  nbTet = 2;
1389         break;
1390       case SMDSEntity_Penta:
1391       case SMDSEntity_Quad_Penta:
1392         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1393         break;
1394       default:
1395         nbVariants = 0;
1396       }
1397       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1398       {
1399         // check method compliancy with adjacent tetras,
1400         // all found splits must be among facets of tetras described by this method
1401         method = TSplitMethod( nbTet, connVariants[variant] );
1402         if ( hasAdjacentSplits && method._nbTetra > 0 )
1403         {
1404           bool facetCreated = true;
1405           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1406           {
1407             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1408             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1409               facetCreated = method.hasFacet( *facet );
1410           }
1411           if ( !facetCreated )
1412             method = TSplitMethod(0); // incompatible method
1413         }
1414       }
1415     }
1416     if ( method._nbTetra < 1 )
1417     {
1418       // No standard method is applicable, use a generic solution:
1419       // each facet of a volume is split into triangles and
1420       // each of triangles and a volume barycenter form a tetrahedron.
1421
1422       int* connectivity = new int[ maxTetConnSize + 1 ];
1423       method._connectivity = connectivity;
1424       method._ownConn = true;
1425       method._baryNode = true;
1426
1427       int connSize = 0;
1428       int baryCenInd = vol.NbNodes();
1429       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1430       {
1431         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1432         const int*   nInd = vol.GetFaceNodesIndices( iF );
1433         // find common node of triangle facets of tetra to create
1434         int iCommon = 0; // index in linear numeration
1435         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1436         if ( !triaSplits.empty() )
1437         {
1438           // by found facets
1439           const TTriangleFacet* facet = &triaSplits.front();
1440           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1441             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1442                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1443               break;
1444         }
1445         else if ( nbNodes > 3 && !is24TetMode )
1446         {
1447           // find the best method of splitting into triangles by aspect ratio
1448           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1449           map< double, int > badness2iCommon;
1450           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1451           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1452           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1453             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1454             {
1455               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1456                                       nodes[ iQ*((iLast-1)%nbNodes)],
1457                                       nodes[ iQ*((iLast  )%nbNodes)]);
1458               double badness = getBadRate( &tria, aspectRatio );
1459               badness2iCommon.insert( make_pair( badness, iCommon ));
1460             }
1461           // use iCommon with lowest badness
1462           iCommon = badness2iCommon.begin()->second;
1463         }
1464         if ( iCommon >= nbNodes )
1465           iCommon = 0; // something wrong
1466
1467         // fill connectivity of tetrahedra based on a current face
1468         int nbTet = nbNodes - 2;
1469         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1470         {
1471           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1472           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1473           nbTet = nbNodes;
1474           for ( int i = 0; i < nbTet; ++i )
1475           {
1476             int i1 = i, i2 = (i+1) % nbNodes;
1477             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1478             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1479             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1480             connectivity[ connSize++ ] = faceBaryCenInd;
1481             connectivity[ connSize++ ] = baryCenInd;
1482           }
1483         }
1484         else
1485         {
1486           for ( int i = 0; i < nbTet; ++i )
1487           {
1488             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1489             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1490             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1491             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1492             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1493             connectivity[ connSize++ ] = baryCenInd;
1494           }
1495         }
1496         method._nbTetra += nbTet;
1497       }
1498       connectivity[ connSize++ ] = -1;
1499     }
1500     return method;
1501   }
1502   //================================================================================
1503   /*!
1504    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1505    */
1506   //================================================================================
1507
1508   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1509   {
1510     // find the tetrahedron including the three nodes of facet
1511     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1512     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1513     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1514     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1515     while ( volIt1->more() )
1516     {
1517       const SMDS_MeshElement* v = volIt1->next();
1518       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1519         continue;
1520       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1521       while ( volIt2->more() )
1522         if ( v != volIt2->next() )
1523           continue;
1524       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1525       while ( volIt3->more() )
1526         if ( v == volIt3->next() )
1527           return true;
1528     }
1529     return false;
1530   }
1531
1532   //=======================================================================
1533   /*!
1534    * \brief A key of a face of volume
1535    */
1536   //=======================================================================
1537
1538   struct TVolumeFaceKey: pair< int, pair< int, int> >
1539   {
1540     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1541     {
1542       TIDSortedNodeSet sortedNodes;
1543       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1544       int nbNodes = vol.NbFaceNodes( iF );
1545       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1546       for ( int i = 0; i < nbNodes; i += iQ )
1547         sortedNodes.insert( fNodes[i] );
1548       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1549       first = (*(n++))->GetID();
1550       second.first = (*(n++))->GetID();
1551       second.second = (*(n++))->GetID();
1552     }
1553   };
1554 } // namespace
1555
1556 //=======================================================================
1557 //function : SplitVolumesIntoTetra
1558 //purpose  : Split volumic elements into tetrahedra.
1559 //=======================================================================
1560
1561 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1562                                               const int                theMethodFlags)
1563 {
1564   // std-like iterator on coordinates of nodes of mesh element
1565   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1566   NXyzIterator xyzEnd;
1567
1568   SMDS_VolumeTool    volTool;
1569   SMESH_MesherHelper helper( *GetMesh());
1570
1571   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1572   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1573   
1574   SMESH_SequenceOfElemPtr newNodes, newElems;
1575
1576   // map face of volume to it's baricenrtic node
1577   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1578   double bc[3];
1579
1580   TIDSortedElemSet::const_iterator elem = theElems.begin();
1581   for ( ; elem != theElems.end(); ++elem )
1582   {
1583     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1584     if ( geomType <= SMDSEntity_Quad_Tetra )
1585       continue; // tetra or face or ...
1586
1587     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1588
1589     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1590     if ( splitMethod._nbTetra < 1 ) continue;
1591
1592     // find submesh to add new tetras to
1593     if ( !subMesh || !subMesh->Contains( *elem ))
1594     {
1595       int shapeID = FindShape( *elem );
1596       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1597       subMesh = GetMeshDS()->MeshElements( shapeID );
1598     }
1599     int iQ;
1600     if ( (*elem)->IsQuadratic() )
1601     {
1602       iQ = 2;
1603       // add quadratic links to the helper
1604       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1605       {
1606         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1607         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1608           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1609       }
1610       helper.SetIsQuadratic( true );
1611     }
1612     else
1613     {
1614       iQ = 1;
1615       helper.SetIsQuadratic( false );
1616     }
1617     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1618     helper.SetElementsOnShape( true );
1619     if ( splitMethod._baryNode )
1620     {
1621       // make a node at barycenter
1622       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1623       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1624       nodes.push_back( gcNode );
1625       newNodes.Append( gcNode );
1626     }
1627     if ( !splitMethod._faceBaryNode.empty() )
1628     {
1629       // make or find baricentric nodes of faces
1630       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1631       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1632       {
1633         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1634           volFace2BaryNode.insert
1635           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1636         if ( !f_n->second )
1637         {
1638           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1639           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1640         }
1641         nodes.push_back( iF_n->second = f_n->second );
1642       }
1643     }
1644
1645     // make tetras
1646     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1647     const int* tetConn = splitMethod._connectivity;
1648     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1649       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1650                                                        nodes[ tetConn[1] ],
1651                                                        nodes[ tetConn[2] ],
1652                                                        nodes[ tetConn[3] ]));
1653
1654     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1655
1656     // Split faces on sides of the split volume
1657
1658     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1659     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1660     {
1661       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1662       if ( nbNodes < 4 ) continue;
1663
1664       // find an existing face
1665       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1666                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1667       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1668       {
1669         // make triangles
1670         helper.SetElementsOnShape( false );
1671         vector< const SMDS_MeshElement* > triangles;
1672
1673         // find submesh to add new triangles in
1674         if ( !fSubMesh || !fSubMesh->Contains( face ))
1675         {
1676           int shapeID = FindShape( face );
1677           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1678         }
1679         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1680         if ( iF_n != splitMethod._faceBaryNode.end() )
1681         {
1682           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1683           {
1684             const SMDS_MeshNode* n1 = fNodes[iN];
1685             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1686             const SMDS_MeshNode *n3 = iF_n->second;
1687             if ( !volTool.IsFaceExternal( iF ))
1688               swap( n2, n3 );
1689             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1690
1691             if ( n3->getshapeId() < 1 )
1692               fSubMesh->AddNode( n3 );
1693           }
1694         }
1695         else
1696         {
1697           // among possible triangles create ones discribed by split method
1698           const int* nInd = volTool.GetFaceNodesIndices( iF );
1699           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1700           int iCom = 0; // common node of triangle faces to split into
1701           list< TTriangleFacet > facets;
1702           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1703           {
1704             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1705                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1706                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1707             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1708                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1709                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1710             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1711             {
1712               facets.push_back( t012 );
1713               facets.push_back( t023 );
1714               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1715                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1716                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1717                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1718               break;
1719             }
1720           }
1721           list< TTriangleFacet >::iterator facet = facets.begin();
1722           for ( ; facet != facets.end(); ++facet )
1723           {
1724             if ( !volTool.IsFaceExternal( iF ))
1725               swap( facet->_n2, facet->_n3 );
1726             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1727                                                  volNodes[ facet->_n2 ],
1728                                                  volNodes[ facet->_n3 ]));
1729           }
1730         }
1731         for ( int i = 0; i < triangles.size(); ++i )
1732         {
1733           if ( !triangles[i] ) continue;
1734           if ( fSubMesh )
1735             fSubMesh->AddElement( triangles[i]);
1736           newElems.Append( triangles[i] );
1737         }
1738         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1739         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1740       }
1741
1742     } // loop on volume faces to split them into triangles
1743
1744     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1745
1746   } // loop on volumes to split
1747
1748   myLastCreatedNodes = newNodes;
1749   myLastCreatedElems = newElems;
1750 }
1751
1752 //=======================================================================
1753 //function : AddToSameGroups
1754 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1755 //=======================================================================
1756
1757 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1758                                         const SMDS_MeshElement* elemInGroups,
1759                                         SMESHDS_Mesh *          aMesh)
1760 {
1761   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1762   if (!groups.empty()) {
1763     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1764     for ( ; grIt != groups.end(); grIt++ ) {
1765       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1766       if ( group && group->Contains( elemInGroups ))
1767         group->SMDSGroup().Add( elemToAdd );
1768     }
1769   }
1770 }
1771
1772
1773 //=======================================================================
1774 //function : RemoveElemFromGroups
1775 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1776 //=======================================================================
1777 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1778                                              SMESHDS_Mesh *          aMesh)
1779 {
1780   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1781   if (!groups.empty())
1782   {
1783     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1784     for (; GrIt != groups.end(); GrIt++)
1785     {
1786       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1787       if (!grp || grp->IsEmpty()) continue;
1788       grp->SMDSGroup().Remove(removeelem);
1789     }
1790   }
1791 }
1792
1793 //================================================================================
1794 /*!
1795  * \brief Replace elemToRm by elemToAdd in the all groups
1796  */
1797 //================================================================================
1798
1799 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1800                                             const SMDS_MeshElement* elemToAdd,
1801                                             SMESHDS_Mesh *          aMesh)
1802 {
1803   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1804   if (!groups.empty()) {
1805     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1806     for ( ; grIt != groups.end(); grIt++ ) {
1807       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1808       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1809         group->SMDSGroup().Add( elemToAdd );
1810     }
1811   }
1812 }
1813
1814 //================================================================================
1815 /*!
1816  * \brief Replace elemToRm by elemToAdd in the all groups
1817  */
1818 //================================================================================
1819
1820 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1821                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1822                                             SMESHDS_Mesh *                         aMesh)
1823 {
1824   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1825   if (!groups.empty())
1826   {
1827     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1828     for ( ; grIt != groups.end(); grIt++ ) {
1829       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1830       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1831         for ( int i = 0; i < elemToAdd.size(); ++i )
1832           group->SMDSGroup().Add( elemToAdd[ i ] );
1833     }
1834   }
1835 }
1836
1837 //=======================================================================
1838 //function : QuadToTri
1839 //purpose  : Cut quadrangles into triangles.
1840 //           theCrit is used to select a diagonal to cut
1841 //=======================================================================
1842
1843 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1844                                   const bool         the13Diag)
1845 {
1846   myLastCreatedElems.Clear();
1847   myLastCreatedNodes.Clear();
1848
1849   MESSAGE( "::QuadToTri()" );
1850
1851   SMESHDS_Mesh * aMesh = GetMeshDS();
1852
1853   Handle(Geom_Surface) surface;
1854   SMESH_MesherHelper   helper( *GetMesh() );
1855
1856   TIDSortedElemSet::iterator itElem;
1857   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1858     const SMDS_MeshElement* elem = *itElem;
1859     if ( !elem || elem->GetType() != SMDSAbs_Face )
1860       continue;
1861     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1862     if(!isquad) continue;
1863
1864     if(elem->NbNodes()==4) {
1865       // retrieve element nodes
1866       const SMDS_MeshNode* aNodes [4];
1867       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1868       int i = 0;
1869       while ( itN->more() )
1870         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1871
1872       int aShapeId = FindShape( elem );
1873       const SMDS_MeshElement* newElem1 = 0;
1874       const SMDS_MeshElement* newElem2 = 0;
1875       if ( the13Diag ) {
1876         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1877         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1878       }
1879       else {
1880         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1881         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1882       }
1883       myLastCreatedElems.Append(newElem1);
1884       myLastCreatedElems.Append(newElem2);
1885       // put a new triangle on the same shape and add to the same groups
1886       if ( aShapeId )
1887         {
1888           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1889           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1890         }
1891       AddToSameGroups( newElem1, elem, aMesh );
1892       AddToSameGroups( newElem2, elem, aMesh );
1893       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1894       aMesh->RemoveElement( elem );
1895     }
1896
1897     // Quadratic quadrangle
1898
1899     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1900
1901       // get surface elem is on
1902       int aShapeId = FindShape( elem );
1903       if ( aShapeId != helper.GetSubShapeID() ) {
1904         surface.Nullify();
1905         TopoDS_Shape shape;
1906         if ( aShapeId > 0 )
1907           shape = aMesh->IndexToShape( aShapeId );
1908         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1909           TopoDS_Face face = TopoDS::Face( shape );
1910           surface = BRep_Tool::Surface( face );
1911           if ( !surface.IsNull() )
1912             helper.SetSubShape( shape );
1913         }
1914       }
1915
1916       const SMDS_MeshNode* aNodes [8];
1917       const SMDS_MeshNode* inFaceNode = 0;
1918       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1919       int i = 0;
1920       while ( itN->more() ) {
1921         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1922         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1923              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1924         {
1925           inFaceNode = aNodes[ i-1 ];
1926         }
1927       }
1928
1929       // find middle point for (0,1,2,3)
1930       // and create a node in this point;
1931       gp_XYZ p( 0,0,0 );
1932       if ( surface.IsNull() ) {
1933         for(i=0; i<4; i++)
1934           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1935         p /= 4;
1936       }
1937       else {
1938         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1939         gp_XY uv( 0,0 );
1940         for(i=0; i<4; i++)
1941           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1942         uv /= 4.;
1943         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1944       }
1945       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1946       myLastCreatedNodes.Append(newN);
1947
1948       // create a new element
1949       const SMDS_MeshElement* newElem1 = 0;
1950       const SMDS_MeshElement* newElem2 = 0;
1951       if ( the13Diag ) {
1952         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1953                                   aNodes[6], aNodes[7], newN );
1954         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1955                                   newN,      aNodes[4], aNodes[5] );
1956       }
1957       else {
1958         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1959                                   aNodes[7], aNodes[4], newN );
1960         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1961                                   newN,      aNodes[5], aNodes[6] );
1962       }
1963       myLastCreatedElems.Append(newElem1);
1964       myLastCreatedElems.Append(newElem2);
1965       // put a new triangle on the same shape and add to the same groups
1966       if ( aShapeId )
1967         {
1968           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1969           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1970         }
1971       AddToSameGroups( newElem1, elem, aMesh );
1972       AddToSameGroups( newElem2, elem, aMesh );
1973       aMesh->RemoveElement( elem );
1974     }
1975   }
1976
1977   return true;
1978 }
1979
1980 //=======================================================================
1981 //function : getAngle
1982 //purpose  :
1983 //=======================================================================
1984
1985 double getAngle(const SMDS_MeshElement * tr1,
1986                 const SMDS_MeshElement * tr2,
1987                 const SMDS_MeshNode *    n1,
1988                 const SMDS_MeshNode *    n2)
1989 {
1990   double angle = 2*PI; // bad angle
1991
1992   // get normals
1993   SMESH::Controls::TSequenceOfXYZ P1, P2;
1994   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1995        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1996     return angle;
1997   gp_Vec N1,N2;
1998   if(!tr1->IsQuadratic())
1999     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2000   else
2001     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2002   if ( N1.SquareMagnitude() <= gp::Resolution() )
2003     return angle;
2004   if(!tr2->IsQuadratic())
2005     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2006   else
2007     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2008   if ( N2.SquareMagnitude() <= gp::Resolution() )
2009     return angle;
2010
2011   // find the first diagonal node n1 in the triangles:
2012   // take in account a diagonal link orientation
2013   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2014   for ( int t = 0; t < 2; t++ ) {
2015     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2016     int i = 0, iDiag = -1;
2017     while ( it->more()) {
2018       const SMDS_MeshElement *n = it->next();
2019       if ( n == n1 || n == n2 ) {
2020         if ( iDiag < 0)
2021           iDiag = i;
2022         else {
2023           if ( i - iDiag == 1 )
2024             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2025           else
2026             nFirst[ t ] = n;
2027           break;
2028         }
2029       }
2030       i++;
2031     }
2032   }
2033   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2034     N2.Reverse();
2035
2036   angle = N1.Angle( N2 );
2037   //SCRUTE( angle );
2038   return angle;
2039 }
2040
2041 // =================================================
2042 // class generating a unique ID for a pair of nodes
2043 // and able to return nodes by that ID
2044 // =================================================
2045 class LinkID_Gen {
2046 public:
2047
2048   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2049     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2050   {}
2051
2052   long GetLinkID (const SMDS_MeshNode * n1,
2053                   const SMDS_MeshNode * n2) const
2054   {
2055     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2056   }
2057
2058   bool GetNodes (const long             theLinkID,
2059                  const SMDS_MeshNode* & theNode1,
2060                  const SMDS_MeshNode* & theNode2) const
2061   {
2062     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2063     if ( !theNode1 ) return false;
2064     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2065     if ( !theNode2 ) return false;
2066     return true;
2067   }
2068
2069 private:
2070   LinkID_Gen();
2071   const SMESHDS_Mesh* myMesh;
2072   long                myMaxID;
2073 };
2074
2075
2076 //=======================================================================
2077 //function : TriToQuad
2078 //purpose  : Fuse neighbour triangles into quadrangles.
2079 //           theCrit is used to select a neighbour to fuse with.
2080 //           theMaxAngle is a max angle between element normals at which
2081 //           fusion is still performed.
2082 //=======================================================================
2083
2084 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2085                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2086                                   const double                         theMaxAngle)
2087 {
2088   myLastCreatedElems.Clear();
2089   myLastCreatedNodes.Clear();
2090
2091   MESSAGE( "::TriToQuad()" );
2092
2093   if ( !theCrit.get() )
2094     return false;
2095
2096   SMESHDS_Mesh * aMesh = GetMeshDS();
2097
2098   // Prepare data for algo: build
2099   // 1. map of elements with their linkIDs
2100   // 2. map of linkIDs with their elements
2101
2102   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2103   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2104   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2105   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2106
2107   TIDSortedElemSet::iterator itElem;
2108   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2109     const SMDS_MeshElement* elem = *itElem;
2110     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2111     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2112     if(!IsTria) continue;
2113
2114     // retrieve element nodes
2115     const SMDS_MeshNode* aNodes [4];
2116     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2117     int i = 0;
2118     while ( i<3 )
2119       aNodes[ i++ ] = cast2Node( itN->next() );
2120     aNodes[ 3 ] = aNodes[ 0 ];
2121
2122     // fill maps
2123     for ( i = 0; i < 3; i++ ) {
2124       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2125       // check if elements sharing a link can be fused
2126       itLE = mapLi_listEl.find( link );
2127       if ( itLE != mapLi_listEl.end() ) {
2128         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2129           continue;
2130         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2131         //if ( FindShape( elem ) != FindShape( elem2 ))
2132         //  continue; // do not fuse triangles laying on different shapes
2133         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2134           continue; // avoid making badly shaped quads
2135         (*itLE).second.push_back( elem );
2136       }
2137       else {
2138         mapLi_listEl[ link ].push_back( elem );
2139       }
2140       mapEl_setLi [ elem ].insert( link );
2141     }
2142   }
2143   // Clean the maps from the links shared by a sole element, ie
2144   // links to which only one element is bound in mapLi_listEl
2145
2146   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2147     int nbElems = (*itLE).second.size();
2148     if ( nbElems < 2  ) {
2149       const SMDS_MeshElement* elem = (*itLE).second.front();
2150       SMESH_TLink link = (*itLE).first;
2151       mapEl_setLi[ elem ].erase( link );
2152       if ( mapEl_setLi[ elem ].empty() )
2153         mapEl_setLi.erase( elem );
2154     }
2155   }
2156
2157   // Algo: fuse triangles into quadrangles
2158
2159   while ( ! mapEl_setLi.empty() ) {
2160     // Look for the start element:
2161     // the element having the least nb of shared links
2162     const SMDS_MeshElement* startElem = 0;
2163     int minNbLinks = 4;
2164     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2165       int nbLinks = (*itEL).second.size();
2166       if ( nbLinks < minNbLinks ) {
2167         startElem = (*itEL).first;
2168         minNbLinks = nbLinks;
2169         if ( minNbLinks == 1 )
2170           break;
2171       }
2172     }
2173
2174     // search elements to fuse starting from startElem or links of elements
2175     // fused earlyer - startLinks
2176     list< SMESH_TLink > startLinks;
2177     while ( startElem || !startLinks.empty() ) {
2178       while ( !startElem && !startLinks.empty() ) {
2179         // Get an element to start, by a link
2180         SMESH_TLink linkId = startLinks.front();
2181         startLinks.pop_front();
2182         itLE = mapLi_listEl.find( linkId );
2183         if ( itLE != mapLi_listEl.end() ) {
2184           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2185           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2186           for ( ; itE != listElem.end() ; itE++ )
2187             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2188               startElem = (*itE);
2189           mapLi_listEl.erase( itLE );
2190         }
2191       }
2192
2193       if ( startElem ) {
2194         // Get candidates to be fused
2195         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2196         const SMESH_TLink *link12, *link13;
2197         startElem = 0;
2198         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2199         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2200         ASSERT( !setLi.empty() );
2201         set< SMESH_TLink >::iterator itLi;
2202         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2203         {
2204           const SMESH_TLink & link = (*itLi);
2205           itLE = mapLi_listEl.find( link );
2206           if ( itLE == mapLi_listEl.end() )
2207             continue;
2208
2209           const SMDS_MeshElement* elem = (*itLE).second.front();
2210           if ( elem == tr1 )
2211             elem = (*itLE).second.back();
2212           mapLi_listEl.erase( itLE );
2213           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2214             continue;
2215           if ( tr2 ) {
2216             tr3 = elem;
2217             link13 = &link;
2218           }
2219           else {
2220             tr2 = elem;
2221             link12 = &link;
2222           }
2223
2224           // add other links of elem to list of links to re-start from
2225           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2226           set< SMESH_TLink >::iterator it;
2227           for ( it = links.begin(); it != links.end(); it++ ) {
2228             const SMESH_TLink& link2 = (*it);
2229             if ( link2 != link )
2230               startLinks.push_back( link2 );
2231           }
2232         }
2233
2234         // Get nodes of possible quadrangles
2235         const SMDS_MeshNode *n12 [4], *n13 [4];
2236         bool Ok12 = false, Ok13 = false;
2237         const SMDS_MeshNode *linkNode1, *linkNode2;
2238         if(tr2) {
2239           linkNode1 = link12->first;
2240           linkNode2 = link12->second;
2241           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2242             Ok12 = true;
2243         }
2244         if(tr3) {
2245           linkNode1 = link13->first;
2246           linkNode2 = link13->second;
2247           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2248             Ok13 = true;
2249         }
2250
2251         // Choose a pair to fuse
2252         if ( Ok12 && Ok13 ) {
2253           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2254           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2255           double aBadRate12 = getBadRate( &quad12, theCrit );
2256           double aBadRate13 = getBadRate( &quad13, theCrit );
2257           if (  aBadRate13 < aBadRate12 )
2258             Ok12 = false;
2259           else
2260             Ok13 = false;
2261         }
2262
2263         // Make quadrangles
2264         // and remove fused elems and removed links from the maps
2265         mapEl_setLi.erase( tr1 );
2266         if ( Ok12 ) {
2267           mapEl_setLi.erase( tr2 );
2268           mapLi_listEl.erase( *link12 );
2269           if(tr1->NbNodes()==3) {
2270             const SMDS_MeshElement* newElem = 0;
2271             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2272             myLastCreatedElems.Append(newElem);
2273             AddToSameGroups( newElem, tr1, aMesh );
2274             int aShapeId = tr1->getshapeId();
2275             if ( aShapeId )
2276               {
2277                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2278               }
2279             aMesh->RemoveElement( tr1 );
2280             aMesh->RemoveElement( tr2 );
2281           }
2282           else {
2283             const SMDS_MeshNode* N1 [6];
2284             const SMDS_MeshNode* N2 [6];
2285             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2286             // now we receive following N1 and N2 (using numeration as above image)
2287             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2288             // i.e. first nodes from both arrays determ new diagonal
2289             const SMDS_MeshNode* aNodes[8];
2290             aNodes[0] = N1[0];
2291             aNodes[1] = N1[1];
2292             aNodes[2] = N2[0];
2293             aNodes[3] = N2[1];
2294             aNodes[4] = N1[3];
2295             aNodes[5] = N2[5];
2296             aNodes[6] = N2[3];
2297             aNodes[7] = N1[5];
2298             const SMDS_MeshElement* newElem = 0;
2299             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2300                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2301             myLastCreatedElems.Append(newElem);
2302             AddToSameGroups( newElem, tr1, aMesh );
2303             int aShapeId = tr1->getshapeId();
2304             if ( aShapeId )
2305               {
2306                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2307               }
2308             aMesh->RemoveElement( tr1 );
2309             aMesh->RemoveElement( tr2 );
2310             // remove middle node (9)
2311             GetMeshDS()->RemoveNode( N1[4] );
2312           }
2313         }
2314         else if ( Ok13 ) {
2315           mapEl_setLi.erase( tr3 );
2316           mapLi_listEl.erase( *link13 );
2317           if(tr1->NbNodes()==3) {
2318             const SMDS_MeshElement* newElem = 0;
2319             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2320             myLastCreatedElems.Append(newElem);
2321             AddToSameGroups( newElem, tr1, aMesh );
2322             int aShapeId = tr1->getshapeId();
2323             if ( aShapeId )
2324               {
2325                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2326               }
2327             aMesh->RemoveElement( tr1 );
2328             aMesh->RemoveElement( tr3 );
2329           }
2330           else {
2331             const SMDS_MeshNode* N1 [6];
2332             const SMDS_MeshNode* N2 [6];
2333             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2334             // now we receive following N1 and N2 (using numeration as above image)
2335             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2336             // i.e. first nodes from both arrays determ new diagonal
2337             const SMDS_MeshNode* aNodes[8];
2338             aNodes[0] = N1[0];
2339             aNodes[1] = N1[1];
2340             aNodes[2] = N2[0];
2341             aNodes[3] = N2[1];
2342             aNodes[4] = N1[3];
2343             aNodes[5] = N2[5];
2344             aNodes[6] = N2[3];
2345             aNodes[7] = N1[5];
2346             const SMDS_MeshElement* newElem = 0;
2347             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2348                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2349             myLastCreatedElems.Append(newElem);
2350             AddToSameGroups( newElem, tr1, aMesh );
2351             int aShapeId = tr1->getshapeId();
2352             if ( aShapeId )
2353               {
2354                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2355               }
2356             aMesh->RemoveElement( tr1 );
2357             aMesh->RemoveElement( tr3 );
2358             // remove middle node (9)
2359             GetMeshDS()->RemoveNode( N1[4] );
2360           }
2361         }
2362
2363         // Next element to fuse: the rejected one
2364         if ( tr3 )
2365           startElem = Ok12 ? tr3 : tr2;
2366
2367       } // if ( startElem )
2368     } // while ( startElem || !startLinks.empty() )
2369   } // while ( ! mapEl_setLi.empty() )
2370
2371   return true;
2372 }
2373
2374
2375 /*#define DUMPSO(txt) \
2376 //  cout << txt << endl;
2377 //=============================================================================
2378 //
2379 //
2380 //
2381 //=============================================================================
2382 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2383 {
2384 if ( i1 == i2 )
2385 return;
2386 int tmp = idNodes[ i1 ];
2387 idNodes[ i1 ] = idNodes[ i2 ];
2388 idNodes[ i2 ] = tmp;
2389 gp_Pnt Ptmp = P[ i1 ];
2390 P[ i1 ] = P[ i2 ];
2391 P[ i2 ] = Ptmp;
2392 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2393 }
2394
2395 //=======================================================================
2396 //function : SortQuadNodes
2397 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2398 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2399 //           1 or 2 else 0.
2400 //=======================================================================
2401
2402 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2403 int               idNodes[] )
2404 {
2405   gp_Pnt P[4];
2406   int i;
2407   for ( i = 0; i < 4; i++ ) {
2408     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2409     if ( !n ) return 0;
2410     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2411   }
2412
2413   gp_Vec V1(P[0], P[1]);
2414   gp_Vec V2(P[0], P[2]);
2415   gp_Vec V3(P[0], P[3]);
2416
2417   gp_Vec Cross1 = V1 ^ V2;
2418   gp_Vec Cross2 = V2 ^ V3;
2419
2420   i = 0;
2421   if (Cross1.Dot(Cross2) < 0)
2422   {
2423     Cross1 = V2 ^ V1;
2424     Cross2 = V1 ^ V3;
2425
2426     if (Cross1.Dot(Cross2) < 0)
2427       i = 2;
2428     else
2429       i = 1;
2430     swap ( i, i + 1, idNodes, P );
2431
2432     //     for ( int ii = 0; ii < 4; ii++ ) {
2433     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2434     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2435     //     }
2436   }
2437   return i;
2438 }
2439
2440 //=======================================================================
2441 //function : SortHexaNodes
2442 //purpose  : Set 8 nodes of a hexahedron in a good order.
2443 //           Return success status
2444 //=======================================================================
2445
2446 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2447                                       int               idNodes[] )
2448 {
2449   gp_Pnt P[8];
2450   int i;
2451   DUMPSO( "INPUT: ========================================");
2452   for ( i = 0; i < 8; i++ ) {
2453     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2454     if ( !n ) return false;
2455     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2456     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2457   }
2458   DUMPSO( "========================================");
2459
2460
2461   set<int> faceNodes;  // ids of bottom face nodes, to be found
2462   set<int> checkedId1; // ids of tried 2-nd nodes
2463   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2464   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2465   int iMin, iLoop1 = 0;
2466
2467   // Loop to try the 2-nd nodes
2468
2469   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2470   {
2471     // Find not checked 2-nd node
2472     for ( i = 1; i < 8; i++ )
2473       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2474         int id1 = idNodes[i];
2475         swap ( 1, i, idNodes, P );
2476         checkedId1.insert ( id1 );
2477         break;
2478       }
2479
2480     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2481     // ie that all but meybe one (id3 which is on the same face) nodes
2482     // lay on the same side from the triangle plane.
2483
2484     bool manyInPlane = false; // more than 4 nodes lay in plane
2485     int iLoop2 = 0;
2486     while ( ++iLoop2 < 6 ) {
2487
2488       // get 1-2-3 plane coeffs
2489       Standard_Real A, B, C, D;
2490       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2491       if ( N.SquareMagnitude() > gp::Resolution() )
2492       {
2493         gp_Pln pln ( P[0], N );
2494         pln.Coefficients( A, B, C, D );
2495
2496         // find the node (iMin) closest to pln
2497         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2498         set<int> idInPln;
2499         for ( i = 3; i < 8; i++ ) {
2500           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2501           if ( fabs( dist[i] ) < minDist ) {
2502             minDist = fabs( dist[i] );
2503             iMin = i;
2504           }
2505           if ( fabs( dist[i] ) <= tol )
2506             idInPln.insert( idNodes[i] );
2507         }
2508
2509         // there should not be more than 4 nodes in bottom plane
2510         if ( idInPln.size() > 1 )
2511         {
2512           DUMPSO( "### idInPln.size() = " << idInPln.size());
2513           // idInPlane does not contain the first 3 nodes
2514           if ( manyInPlane || idInPln.size() == 5)
2515             return false; // all nodes in one plane
2516           manyInPlane = true;
2517
2518           // set the 1-st node to be not in plane
2519           for ( i = 3; i < 8; i++ ) {
2520             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2521               DUMPSO( "### Reset 0-th node");
2522               swap( 0, i, idNodes, P );
2523               break;
2524             }
2525           }
2526
2527           // reset to re-check second nodes
2528           leastDist = DBL_MAX;
2529           faceNodes.clear();
2530           checkedId1.clear();
2531           iLoop1 = 0;
2532           break; // from iLoop2;
2533         }
2534
2535         // check that the other 4 nodes are on the same side
2536         bool sameSide = true;
2537         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2538         for ( i = 3; sameSide && i < 8; i++ ) {
2539           if ( i != iMin )
2540             sameSide = ( isNeg == dist[i] <= 0.);
2541         }
2542
2543         // keep best solution
2544         if ( sameSide && minDist < leastDist ) {
2545           leastDist = minDist;
2546           faceNodes.clear();
2547           faceNodes.insert( idNodes[ 1 ] );
2548           faceNodes.insert( idNodes[ 2 ] );
2549           faceNodes.insert( idNodes[ iMin ] );
2550           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2551                   << " leastDist = " << leastDist);
2552           if ( leastDist <= DBL_MIN )
2553             break;
2554         }
2555       }
2556
2557       // set next 3-d node to check
2558       int iNext = 2 + iLoop2;
2559       if ( iNext < 8 ) {
2560         DUMPSO( "Try 2-nd");
2561         swap ( 2, iNext, idNodes, P );
2562       }
2563     } // while ( iLoop2 < 6 )
2564   } // iLoop1
2565
2566   if ( faceNodes.empty() ) return false;
2567
2568   // Put the faceNodes in proper places
2569   for ( i = 4; i < 8; i++ ) {
2570     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2571       // find a place to put
2572       int iTo = 1;
2573       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2574         iTo++;
2575       DUMPSO( "Set faceNodes");
2576       swap ( iTo, i, idNodes, P );
2577     }
2578   }
2579
2580
2581   // Set nodes of the found bottom face in good order
2582   DUMPSO( " Found bottom face: ");
2583   i = SortQuadNodes( theMesh, idNodes );
2584   if ( i ) {
2585     gp_Pnt Ptmp = P[ i ];
2586     P[ i ] = P[ i+1 ];
2587     P[ i+1 ] = Ptmp;
2588   }
2589   //   else
2590   //     for ( int ii = 0; ii < 4; ii++ ) {
2591   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2592   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2593   //    }
2594
2595   // Gravity center of the top and bottom faces
2596   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2597   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2598
2599   // Get direction from the bottom to the top face
2600   gp_Vec upDir ( aGCb, aGCt );
2601   Standard_Real upDirSize = upDir.Magnitude();
2602   if ( upDirSize <= gp::Resolution() ) return false;
2603   upDir / upDirSize;
2604
2605   // Assure that the bottom face normal points up
2606   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2607   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2608   if ( Nb.Dot( upDir ) < 0 ) {
2609     DUMPSO( "Reverse bottom face");
2610     swap( 1, 3, idNodes, P );
2611   }
2612
2613   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2614   Standard_Real minDist = DBL_MAX;
2615   for ( i = 4; i < 8; i++ ) {
2616     // projection of P[i] to the plane defined by P[0] and upDir
2617     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2618     Standard_Real sqDist = P[0].SquareDistance( Pp );
2619     if ( sqDist < minDist ) {
2620       minDist = sqDist;
2621       iMin = i;
2622     }
2623   }
2624   DUMPSO( "Set 4-th");
2625   swap ( 4, iMin, idNodes, P );
2626
2627   // Set nodes of the top face in good order
2628   DUMPSO( "Sort top face");
2629   i = SortQuadNodes( theMesh, &idNodes[4] );
2630   if ( i ) {
2631     i += 4;
2632     gp_Pnt Ptmp = P[ i ];
2633     P[ i ] = P[ i+1 ];
2634     P[ i+1 ] = Ptmp;
2635   }
2636
2637   // Assure that direction of the top face normal is from the bottom face
2638   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2639   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2640   if ( Nt.Dot( upDir ) < 0 ) {
2641     DUMPSO( "Reverse top face");
2642     swap( 5, 7, idNodes, P );
2643   }
2644
2645   //   DUMPSO( "OUTPUT: ========================================");
2646   //   for ( i = 0; i < 8; i++ ) {
2647   //     float *p = ugrid->GetPoint(idNodes[i]);
2648   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2649   //   }
2650
2651   return true;
2652 }*/
2653
2654 //================================================================================
2655 /*!
2656  * \brief Return nodes linked to the given one
2657  * \param theNode - the node
2658  * \param linkedNodes - the found nodes
2659  * \param type - the type of elements to check
2660  *
2661  * Medium nodes are ignored
2662  */
2663 //================================================================================
2664
2665 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2666                                        TIDSortedElemSet &   linkedNodes,
2667                                        SMDSAbs_ElementType  type )
2668 {
2669   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2670   while ( elemIt->more() )
2671   {
2672     const SMDS_MeshElement* elem = elemIt->next();
2673     if(elem->GetType() == SMDSAbs_0DElement)
2674       continue;
2675     
2676     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2677     if ( elem->GetType() == SMDSAbs_Volume )
2678     {
2679       SMDS_VolumeTool vol( elem );
2680       while ( nodeIt->more() ) {
2681         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2682         if ( theNode != n && vol.IsLinked( theNode, n ))
2683           linkedNodes.insert( n );
2684       }
2685     }
2686     else
2687     {
2688       for ( int i = 0; nodeIt->more(); ++i ) {
2689         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2690         if ( n == theNode ) {
2691           int iBefore = i - 1;
2692           int iAfter  = i + 1;
2693           if ( elem->IsQuadratic() ) {
2694             int nb = elem->NbNodes() / 2;
2695             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2696             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2697           }
2698           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2699           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2700         }
2701       }
2702     }
2703   }
2704 }
2705
2706 //=======================================================================
2707 //function : laplacianSmooth
2708 //purpose  : pulls theNode toward the center of surrounding nodes directly
2709 //           connected to that node along an element edge
2710 //=======================================================================
2711
2712 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2713                      const Handle(Geom_Surface)&          theSurface,
2714                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2715 {
2716   // find surrounding nodes
2717
2718   TIDSortedElemSet nodeSet;
2719   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2720
2721   // compute new coodrs
2722
2723   double coord[] = { 0., 0., 0. };
2724   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2725   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2726     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2727     if ( theSurface.IsNull() ) { // smooth in 3D
2728       coord[0] += node->X();
2729       coord[1] += node->Y();
2730       coord[2] += node->Z();
2731     }
2732     else { // smooth in 2D
2733       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2734       gp_XY* uv = theUVMap[ node ];
2735       coord[0] += uv->X();
2736       coord[1] += uv->Y();
2737     }
2738   }
2739   int nbNodes = nodeSet.size();
2740   if ( !nbNodes )
2741     return;
2742   coord[0] /= nbNodes;
2743   coord[1] /= nbNodes;
2744
2745   if ( !theSurface.IsNull() ) {
2746     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2747     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2748     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2749     coord[0] = p3d.X();
2750     coord[1] = p3d.Y();
2751     coord[2] = p3d.Z();
2752   }
2753   else
2754     coord[2] /= nbNodes;
2755
2756   // move node
2757
2758   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2759 }
2760
2761 //=======================================================================
2762 //function : centroidalSmooth
2763 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2764 //           surrounding elements
2765 //=======================================================================
2766
2767 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2768                       const Handle(Geom_Surface)&          theSurface,
2769                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2770 {
2771   gp_XYZ aNewXYZ(0.,0.,0.);
2772   SMESH::Controls::Area anAreaFunc;
2773   double totalArea = 0.;
2774   int nbElems = 0;
2775
2776   // compute new XYZ
2777
2778   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2779   while ( elemIt->more() )
2780   {
2781     const SMDS_MeshElement* elem = elemIt->next();
2782     nbElems++;
2783
2784     gp_XYZ elemCenter(0.,0.,0.);
2785     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2786     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2787     int nn = elem->NbNodes();
2788     if(elem->IsQuadratic()) nn = nn/2;
2789     int i=0;
2790     //while ( itN->more() ) {
2791     while ( i<nn ) {
2792       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2793       i++;
2794       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2795       aNodePoints.push_back( aP );
2796       if ( !theSurface.IsNull() ) { // smooth in 2D
2797         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2798         gp_XY* uv = theUVMap[ aNode ];
2799         aP.SetCoord( uv->X(), uv->Y(), 0. );
2800       }
2801       elemCenter += aP;
2802     }
2803     double elemArea = anAreaFunc.GetValue( aNodePoints );
2804     totalArea += elemArea;
2805     elemCenter /= nn;
2806     aNewXYZ += elemCenter * elemArea;
2807   }
2808   aNewXYZ /= totalArea;
2809   if ( !theSurface.IsNull() ) {
2810     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2811     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2812   }
2813
2814   // move node
2815
2816   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2817 }
2818
2819 //=======================================================================
2820 //function : getClosestUV
2821 //purpose  : return UV of closest projection
2822 //=======================================================================
2823
2824 static bool getClosestUV (Extrema_GenExtPS& projector,
2825                           const gp_Pnt&     point,
2826                           gp_XY &           result)
2827 {
2828   projector.Perform( point );
2829   if ( projector.IsDone() ) {
2830     double u, v, minVal = DBL_MAX;
2831     for ( int i = projector.NbExt(); i > 0; i-- )
2832       if ( projector.Value( i ) < minVal ) {
2833         minVal = projector.Value( i );
2834         projector.Point( i ).Parameter( u, v );
2835       }
2836     result.SetCoord( u, v );
2837     return true;
2838   }
2839   return false;
2840 }
2841
2842 //=======================================================================
2843 //function : Smooth
2844 //purpose  : Smooth theElements during theNbIterations or until a worst
2845 //           element has aspect ratio <= theTgtAspectRatio.
2846 //           Aspect Ratio varies in range [1.0, inf].
2847 //           If theElements is empty, the whole mesh is smoothed.
2848 //           theFixedNodes contains additionally fixed nodes. Nodes built
2849 //           on edges and boundary nodes are always fixed.
2850 //=======================================================================
2851
2852 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2853                                set<const SMDS_MeshNode*> & theFixedNodes,
2854                                const SmoothMethod          theSmoothMethod,
2855                                const int                   theNbIterations,
2856                                double                      theTgtAspectRatio,
2857                                const bool                  the2D)
2858 {
2859   myLastCreatedElems.Clear();
2860   myLastCreatedNodes.Clear();
2861
2862   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2863
2864   if ( theTgtAspectRatio < 1.0 )
2865     theTgtAspectRatio = 1.0;
2866
2867   const double disttol = 1.e-16;
2868
2869   SMESH::Controls::AspectRatio aQualityFunc;
2870
2871   SMESHDS_Mesh* aMesh = GetMeshDS();
2872
2873   if ( theElems.empty() ) {
2874     // add all faces to theElems
2875     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2876     while ( fIt->more() ) {
2877       const SMDS_MeshElement* face = fIt->next();
2878       theElems.insert( face );
2879     }
2880   }
2881   // get all face ids theElems are on
2882   set< int > faceIdSet;
2883   TIDSortedElemSet::iterator itElem;
2884   if ( the2D )
2885     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2886       int fId = FindShape( *itElem );
2887       // check that corresponding submesh exists and a shape is face
2888       if (fId &&
2889           faceIdSet.find( fId ) == faceIdSet.end() &&
2890           aMesh->MeshElements( fId )) {
2891         TopoDS_Shape F = aMesh->IndexToShape( fId );
2892         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2893           faceIdSet.insert( fId );
2894       }
2895     }
2896   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2897
2898   // ===============================================
2899   // smooth elements on each TopoDS_Face separately
2900   // ===============================================
2901
2902   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2903   for ( ; fId != faceIdSet.rend(); ++fId ) {
2904     // get face surface and submesh
2905     Handle(Geom_Surface) surface;
2906     SMESHDS_SubMesh* faceSubMesh = 0;
2907     TopoDS_Face face;
2908     double fToler2 = 0, f,l;
2909     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2910     bool isUPeriodic = false, isVPeriodic = false;
2911     if ( *fId ) {
2912       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2913       surface = BRep_Tool::Surface( face );
2914       faceSubMesh = aMesh->MeshElements( *fId );
2915       fToler2 = BRep_Tool::Tolerance( face );
2916       fToler2 *= fToler2 * 10.;
2917       isUPeriodic = surface->IsUPeriodic();
2918       if ( isUPeriodic )
2919         surface->UPeriod();
2920       isVPeriodic = surface->IsVPeriodic();
2921       if ( isVPeriodic )
2922         surface->VPeriod();
2923       surface->Bounds( u1, u2, v1, v2 );
2924     }
2925     // ---------------------------------------------------------
2926     // for elements on a face, find movable and fixed nodes and
2927     // compute UV for them
2928     // ---------------------------------------------------------
2929     bool checkBoundaryNodes = false;
2930     bool isQuadratic = false;
2931     set<const SMDS_MeshNode*> setMovableNodes;
2932     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2933     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2934     list< const SMDS_MeshElement* > elemsOnFace;
2935
2936     Extrema_GenExtPS projector;
2937     GeomAdaptor_Surface surfAdaptor;
2938     if ( !surface.IsNull() ) {
2939       surfAdaptor.Load( surface );
2940       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2941     }
2942     int nbElemOnFace = 0;
2943     itElem = theElems.begin();
2944     // loop on not yet smoothed elements: look for elems on a face
2945     while ( itElem != theElems.end() ) {
2946       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2947         break; // all elements found
2948
2949       const SMDS_MeshElement* elem = *itElem;
2950       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2951            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2952         ++itElem;
2953         continue;
2954       }
2955       elemsOnFace.push_back( elem );
2956       theElems.erase( itElem++ );
2957       nbElemOnFace++;
2958
2959       if ( !isQuadratic )
2960         isQuadratic = elem->IsQuadratic();
2961
2962       // get movable nodes of elem
2963       const SMDS_MeshNode* node;
2964       SMDS_TypeOfPosition posType;
2965       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2966       int nn = 0, nbn =  elem->NbNodes();
2967       if(elem->IsQuadratic())
2968         nbn = nbn/2;
2969       while ( nn++ < nbn ) {
2970         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2971         const SMDS_PositionPtr& pos = node->GetPosition();
2972         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2973         if (posType != SMDS_TOP_EDGE &&
2974             posType != SMDS_TOP_VERTEX &&
2975             theFixedNodes.find( node ) == theFixedNodes.end())
2976         {
2977           // check if all faces around the node are on faceSubMesh
2978           // because a node on edge may be bound to face
2979           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2980           bool all = true;
2981           if ( faceSubMesh ) {
2982             while ( eIt->more() && all ) {
2983               const SMDS_MeshElement* e = eIt->next();
2984               all = faceSubMesh->Contains( e );
2985             }
2986           }
2987           if ( all )
2988             setMovableNodes.insert( node );
2989           else
2990             checkBoundaryNodes = true;
2991         }
2992         if ( posType == SMDS_TOP_3DSPACE )
2993           checkBoundaryNodes = true;
2994       }
2995
2996       if ( surface.IsNull() )
2997         continue;
2998
2999       // get nodes to check UV
3000       list< const SMDS_MeshNode* > uvCheckNodes;
3001       itN = elem->nodesIterator();
3002       nn = 0; nbn =  elem->NbNodes();
3003       if(elem->IsQuadratic())
3004         nbn = nbn/2;
3005       while ( nn++ < nbn ) {
3006         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3007         if ( uvMap.find( node ) == uvMap.end() )
3008           uvCheckNodes.push_back( node );
3009         // add nodes of elems sharing node
3010         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3011         //         while ( eIt->more() ) {
3012         //           const SMDS_MeshElement* e = eIt->next();
3013         //           if ( e != elem ) {
3014         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3015         //             while ( nIt->more() ) {
3016         //               const SMDS_MeshNode* n =
3017         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3018         //               if ( uvMap.find( n ) == uvMap.end() )
3019         //                 uvCheckNodes.push_back( n );
3020         //             }
3021         //           }
3022         //         }
3023       }
3024       // check UV on face
3025       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3026       for ( ; n != uvCheckNodes.end(); ++n ) {
3027         node = *n;
3028         gp_XY uv( 0, 0 );
3029         const SMDS_PositionPtr& pos = node->GetPosition();
3030         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3031         // get existing UV
3032         switch ( posType ) {
3033         case SMDS_TOP_FACE: {
3034           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3035           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3036           break;
3037         }
3038         case SMDS_TOP_EDGE: {
3039           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3040           Handle(Geom2d_Curve) pcurve;
3041           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3042             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3043           if ( !pcurve.IsNull() ) {
3044             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3045             uv = pcurve->Value( u ).XY();
3046           }
3047           break;
3048         }
3049         case SMDS_TOP_VERTEX: {
3050           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3051           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3052             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3053           break;
3054         }
3055         default:;
3056         }
3057         // check existing UV
3058         bool project = true;
3059         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3060         double dist1 = DBL_MAX, dist2 = 0;
3061         if ( posType != SMDS_TOP_3DSPACE ) {
3062           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3063           project = dist1 > fToler2;
3064         }
3065         if ( project ) { // compute new UV
3066           gp_XY newUV;
3067           if ( !getClosestUV( projector, pNode, newUV )) {
3068             MESSAGE("Node Projection Failed " << node);
3069           }
3070           else {
3071             if ( isUPeriodic )
3072               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3073             if ( isVPeriodic )
3074               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3075             // check new UV
3076             if ( posType != SMDS_TOP_3DSPACE )
3077               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3078             if ( dist2 < dist1 )
3079               uv = newUV;
3080           }
3081         }
3082         // store UV in the map
3083         listUV.push_back( uv );
3084         uvMap.insert( make_pair( node, &listUV.back() ));
3085       }
3086     } // loop on not yet smoothed elements
3087
3088     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3089       checkBoundaryNodes = true;
3090
3091     // fix nodes on mesh boundary
3092
3093     if ( checkBoundaryNodes ) {
3094       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3095       map< NLink, int >::iterator link_nb;
3096       // put all elements links to linkNbMap
3097       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3098       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3099         const SMDS_MeshElement* elem = (*elemIt);
3100         int nbn =  elem->NbNodes();
3101         if(elem->IsQuadratic())
3102           nbn = nbn/2;
3103         // loop on elem links: insert them in linkNbMap
3104         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3105         for ( int iN = 0; iN < nbn; ++iN ) {
3106           curNode = elem->GetNode( iN );
3107           NLink link;
3108           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3109           else                      link = make_pair( prevNode , curNode );
3110           prevNode = curNode;
3111           link_nb = linkNbMap.find( link );
3112           if ( link_nb == linkNbMap.end() )
3113             linkNbMap.insert( make_pair ( link, 1 ));
3114           else
3115             link_nb->second++;
3116         }
3117       }
3118       // remove nodes that are in links encountered only once from setMovableNodes
3119       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3120         if ( link_nb->second == 1 ) {
3121           setMovableNodes.erase( link_nb->first.first );
3122           setMovableNodes.erase( link_nb->first.second );
3123         }
3124       }
3125     }
3126
3127     // -----------------------------------------------------
3128     // for nodes on seam edge, compute one more UV ( uvMap2 );
3129     // find movable nodes linked to nodes on seam and which
3130     // are to be smoothed using the second UV ( uvMap2 )
3131     // -----------------------------------------------------
3132
3133     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3134     if ( !surface.IsNull() ) {
3135       TopExp_Explorer eExp( face, TopAbs_EDGE );
3136       for ( ; eExp.More(); eExp.Next() ) {
3137         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3138         if ( !BRep_Tool::IsClosed( edge, face ))
3139           continue;
3140         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3141         if ( !sm ) continue;
3142         // find out which parameter varies for a node on seam
3143         double f,l;
3144         gp_Pnt2d uv1, uv2;
3145         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3146         if ( pcurve.IsNull() ) continue;
3147         uv1 = pcurve->Value( f );
3148         edge.Reverse();
3149         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3150         if ( pcurve.IsNull() ) continue;
3151         uv2 = pcurve->Value( f );
3152         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3153         // assure uv1 < uv2
3154         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3155           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3156         }
3157         // get nodes on seam and its vertices
3158         list< const SMDS_MeshNode* > seamNodes;
3159         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3160         while ( nSeamIt->more() ) {
3161           const SMDS_MeshNode* node = nSeamIt->next();
3162           if ( !isQuadratic || !IsMedium( node ))
3163             seamNodes.push_back( node );
3164         }
3165         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3166         for ( ; vExp.More(); vExp.Next() ) {
3167           sm = aMesh->MeshElements( vExp.Current() );
3168           if ( sm ) {
3169             nSeamIt = sm->GetNodes();
3170             while ( nSeamIt->more() )
3171               seamNodes.push_back( nSeamIt->next() );
3172           }
3173         }
3174         // loop on nodes on seam
3175         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3176         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3177           const SMDS_MeshNode* nSeam = *noSeIt;
3178           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3179           if ( n_uv == uvMap.end() )
3180             continue;
3181           // set the first UV
3182           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3183           // set the second UV
3184           listUV.push_back( *n_uv->second );
3185           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3186           if ( uvMap2.empty() )
3187             uvMap2 = uvMap; // copy the uvMap contents
3188           uvMap2[ nSeam ] = &listUV.back();
3189
3190           // collect movable nodes linked to ones on seam in nodesNearSeam
3191           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3192           while ( eIt->more() ) {
3193             const SMDS_MeshElement* e = eIt->next();
3194             int nbUseMap1 = 0, nbUseMap2 = 0;
3195             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3196             int nn = 0, nbn =  e->NbNodes();
3197             if(e->IsQuadratic()) nbn = nbn/2;
3198             while ( nn++ < nbn )
3199             {
3200               const SMDS_MeshNode* n =
3201                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3202               if (n == nSeam ||
3203                   setMovableNodes.find( n ) == setMovableNodes.end() )
3204                 continue;
3205               // add only nodes being closer to uv2 than to uv1
3206               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3207                            0.5 * ( n->Y() + nSeam->Y() ),
3208                            0.5 * ( n->Z() + nSeam->Z() ));
3209               gp_XY uv;
3210               getClosestUV( projector, pMid, uv );
3211               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3212                 nodesNearSeam.insert( n );
3213                 nbUseMap2++;
3214               }
3215               else
3216                 nbUseMap1++;
3217             }
3218             // for centroidalSmooth all element nodes must
3219             // be on one side of a seam
3220             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3221               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3222               nn = 0;
3223               while ( nn++ < nbn ) {
3224                 const SMDS_MeshNode* n =
3225                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3226                 setMovableNodes.erase( n );
3227               }
3228             }
3229           }
3230         } // loop on nodes on seam
3231       } // loop on edge of a face
3232     } // if ( !face.IsNull() )
3233
3234     if ( setMovableNodes.empty() ) {
3235       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3236       continue; // goto next face
3237     }
3238
3239     // -------------
3240     // SMOOTHING //
3241     // -------------
3242
3243     int it = -1;
3244     double maxRatio = -1., maxDisplacement = -1.;
3245     set<const SMDS_MeshNode*>::iterator nodeToMove;
3246     for ( it = 0; it < theNbIterations; it++ ) {
3247       maxDisplacement = 0.;
3248       nodeToMove = setMovableNodes.begin();
3249       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3250         const SMDS_MeshNode* node = (*nodeToMove);
3251         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3252
3253         // smooth
3254         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3255         if ( theSmoothMethod == LAPLACIAN )
3256           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3257         else
3258           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3259
3260         // node displacement
3261         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3262         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3263         if ( aDispl > maxDisplacement )
3264           maxDisplacement = aDispl;
3265       }
3266       // no node movement => exit
3267       //if ( maxDisplacement < 1.e-16 ) {
3268       if ( maxDisplacement < disttol ) {
3269         MESSAGE("-- no node movement --");
3270         break;
3271       }
3272
3273       // check elements quality
3274       maxRatio  = 0;
3275       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3276       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3277         const SMDS_MeshElement* elem = (*elemIt);
3278         if ( !elem || elem->GetType() != SMDSAbs_Face )
3279           continue;
3280         SMESH::Controls::TSequenceOfXYZ aPoints;
3281         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3282           double aValue = aQualityFunc.GetValue( aPoints );
3283           if ( aValue > maxRatio )
3284             maxRatio = aValue;
3285         }
3286       }
3287       if ( maxRatio <= theTgtAspectRatio ) {
3288         MESSAGE("-- quality achived --");
3289         break;
3290       }
3291       if (it+1 == theNbIterations) {
3292         MESSAGE("-- Iteration limit exceeded --");
3293       }
3294     } // smoothing iterations
3295
3296     MESSAGE(" Face id: " << *fId <<
3297             " Nb iterstions: " << it <<
3298             " Displacement: " << maxDisplacement <<
3299             " Aspect Ratio " << maxRatio);
3300
3301     // ---------------------------------------
3302     // new nodes positions are computed,
3303     // record movement in DS and set new UV
3304     // ---------------------------------------
3305     nodeToMove = setMovableNodes.begin();
3306     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3307       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3308       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3309       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3310       if ( node_uv != uvMap.end() ) {
3311         gp_XY* uv = node_uv->second;
3312         node->SetPosition
3313           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3314       }
3315     }
3316
3317     // move medium nodes of quadratic elements
3318     if ( isQuadratic )
3319     {
3320       SMESH_MesherHelper helper( *GetMesh() );
3321       if ( !face.IsNull() )
3322         helper.SetSubShape( face );
3323       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3324       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3325         const SMDS_VtkFace* QF =
3326           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3327         if(QF && QF->IsQuadratic()) {
3328           vector<const SMDS_MeshNode*> Ns;
3329           Ns.reserve(QF->NbNodes()+1);
3330           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3331           while ( anIter->more() )
3332             Ns.push_back( cast2Node(anIter->next()) );
3333           Ns.push_back( Ns[0] );
3334           double x, y, z;
3335           for(int i=0; i<QF->NbNodes(); i=i+2) {
3336             if ( !surface.IsNull() ) {
3337               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3338               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3339               gp_XY uv = ( uv1 + uv2 ) / 2.;
3340               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3341               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3342             }
3343             else {
3344               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3345               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3346               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3347             }
3348             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3349                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3350                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3351               // we have to move i+1 node
3352               aMesh->MoveNode( Ns[i+1], x, y, z );
3353             }
3354           }
3355         }
3356       }
3357     }
3358
3359   } // loop on face ids
3360
3361 }
3362
3363 //=======================================================================
3364 //function : isReverse
3365 //purpose  : Return true if normal of prevNodes is not co-directied with
3366 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3367 //           iNotSame is where prevNodes and nextNodes are different
3368 //=======================================================================
3369
3370 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3371                       vector<const SMDS_MeshNode*> nextNodes,
3372                       const int            nbNodes,
3373                       const int            iNotSame)
3374 {
3375   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3376   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3377
3378   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3379   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3380   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3381   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3382
3383   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3384   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3385   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3386   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3387
3388   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3389
3390   return (vA ^ vB) * vN < 0.0;
3391 }
3392
3393 //=======================================================================
3394 /*!
3395  * \brief Create elements by sweeping an element
3396  * \param elem - element to sweep
3397  * \param newNodesItVec - nodes generated from each node of the element
3398  * \param newElems - generated elements
3399  * \param nbSteps - number of sweeping steps
3400  * \param srcElements - to append elem for each generated element
3401  */
3402 //=======================================================================
3403
3404 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3405                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3406                                     list<const SMDS_MeshElement*>&        newElems,
3407                                     const int                             nbSteps,
3408                                     SMESH_SequenceOfElemPtr&              srcElements)
3409 {
3410   //MESSAGE("sweepElement " << nbSteps);
3411   SMESHDS_Mesh* aMesh = GetMeshDS();
3412
3413   // Loop on elem nodes:
3414   // find new nodes and detect same nodes indices
3415   int nbNodes = elem->NbNodes();
3416   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3417   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3418   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3419   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3420
3421   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3422   vector<int> sames(nbNodes);
3423   vector<bool> issimple(nbNodes);
3424
3425   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3426     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3427     const SMDS_MeshNode*                 node         = nnIt->first;
3428     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3429     if ( listNewNodes.empty() ) {
3430       return;
3431     }
3432
3433     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3434
3435     itNN[ iNode ] = listNewNodes.begin();
3436     prevNod[ iNode ] = node;
3437     nextNod[ iNode ] = listNewNodes.front();
3438     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3439       if ( prevNod[ iNode ] != nextNod [ iNode ])
3440         iNotSameNode = iNode;
3441       else {
3442         iSameNode = iNode;
3443         //nbSame++;
3444         sames[nbSame++] = iNode;
3445       }
3446     }
3447   }
3448
3449   //cerr<<"  nbSame = "<<nbSame<<endl;
3450   if ( nbSame == nbNodes || nbSame > 2) {
3451     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3452     //INFOS( " Too many same nodes of element " << elem->GetID() );
3453     return;
3454   }
3455
3456   //  if( elem->IsQuadratic() && nbSame>0 ) {
3457   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3458   //    return;
3459   //  }
3460
3461   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3462   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3463   if ( nbSame > 0 ) {
3464     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3465     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3466     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3467   }
3468
3469   //if(nbNodes==8)
3470   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3471   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3472   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3473   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3474
3475   // check element orientation
3476   int i0 = 0, i2 = 2;
3477   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3478     //MESSAGE("Reversed elem " << elem );
3479     i0 = 2;
3480     i2 = 0;
3481     if ( nbSame > 0 )
3482       std::swap( iBeforeSame, iAfterSame );
3483   }
3484
3485   // make new elements
3486   const SMDS_MeshElement* lastElem = elem;
3487   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3488     // get next nodes
3489     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3490       if(issimple[iNode]) {
3491         nextNod[ iNode ] = *itNN[ iNode ];
3492         itNN[ iNode ]++;
3493       }
3494       else {
3495         if( elem->GetType()==SMDSAbs_Node ) {
3496           // we have to use two nodes
3497           midlNod[ iNode ] = *itNN[ iNode ];
3498           itNN[ iNode ]++;
3499           nextNod[ iNode ] = *itNN[ iNode ];
3500           itNN[ iNode ]++;
3501         }
3502         else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3503           // we have to use each second node
3504           //itNN[ iNode ]++;
3505           nextNod[ iNode ] = *itNN[ iNode ];
3506           itNN[ iNode ]++;
3507         }
3508         else {
3509           // we have to use two nodes
3510           midlNod[ iNode ] = *itNN[ iNode ];
3511           itNN[ iNode ]++;
3512           nextNod[ iNode ] = *itNN[ iNode ];
3513           itNN[ iNode ]++;
3514         }
3515       }
3516     }
3517     SMDS_MeshElement* aNewElem = 0;
3518     if(!elem->IsPoly()) {
3519       switch ( nbNodes ) {
3520       case 0:
3521         return;
3522       case 1: { // NODE
3523         if ( nbSame == 0 ) {
3524           if(issimple[0])
3525             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3526           else
3527             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3528         }
3529         break;
3530       }
3531       case 2: { // EDGE
3532         if ( nbSame == 0 )
3533           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3534                                     nextNod[ 1 ], nextNod[ 0 ] );
3535         else
3536           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3537                                     nextNod[ iNotSameNode ] );
3538         break;
3539       }
3540
3541       case 3: { // TRIANGLE or quadratic edge
3542         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3543
3544           if ( nbSame == 0 )       // --- pentahedron
3545             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3546                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3547
3548           else if ( nbSame == 1 )  // --- pyramid
3549             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3550                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3551                                          nextNod[ iSameNode ]);
3552
3553           else // 2 same nodes:      --- tetrahedron
3554             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3555                                          nextNod[ iNotSameNode ]);
3556         }
3557         else { // quadratic edge
3558           if(nbSame==0) {     // quadratic quadrangle
3559             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3560                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3561           }
3562           else if(nbSame==1) { // quadratic triangle
3563             if(sames[0]==2) {
3564               return; // medium node on axis
3565             }
3566             else if(sames[0]==0) {
3567               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3568                                         nextNod[2], midlNod[1], prevNod[2]);
3569             }
3570             else { // sames[0]==1
3571               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3572                                         midlNod[0], nextNod[2], prevNod[2]);
3573             }
3574           }
3575           else {
3576             return;
3577           }
3578         }
3579         break;
3580       }
3581       case 4: { // QUADRANGLE
3582
3583         if ( nbSame == 0 )       // --- hexahedron
3584           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3585                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3586
3587         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3588           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3589                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3590                                        nextNod[ iSameNode ]);
3591           newElems.push_back( aNewElem );
3592           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3593                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3594                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3595         }
3596         else if ( nbSame == 2 ) { // pentahedron
3597           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3598             // iBeforeSame is same too
3599             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3600                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3601                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3602           else
3603             // iAfterSame is same too
3604             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3605                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3606                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3607         }
3608         break;
3609       }
3610       case 6: { // quadratic triangle
3611         // create pentahedron with 15 nodes
3612         if(nbSame==0) {
3613           if(i0>0) { // reversed case
3614             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3615                                          nextNod[0], nextNod[2], nextNod[1],
3616                                          prevNod[5], prevNod[4], prevNod[3],
3617                                          nextNod[5], nextNod[4], nextNod[3],
3618                                          midlNod[0], midlNod[2], midlNod[1]);
3619           }
3620           else { // not reversed case
3621             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3622                                          nextNod[0], nextNod[1], nextNod[2],
3623                                          prevNod[3], prevNod[4], prevNod[5],
3624                                          nextNod[3], nextNod[4], nextNod[5],
3625                                          midlNod[0], midlNod[1], midlNod[2]);
3626           }
3627         }
3628         else if(nbSame==1) {
3629           // 2d order pyramid of 13 nodes
3630           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3631           //                                 int n12,int n23,int n34,int n41,
3632           //                                 int n15,int n25,int n35,int n45, int ID);
3633           int n5 = iSameNode;
3634           int n1,n4,n41,n15,n45;
3635           if(i0>0) { // reversed case
3636             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3637             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3638             n41 = n1 + 3;
3639             n15 = n5 + 3;
3640             n45 = n4 + 3;
3641           }
3642           else {
3643             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3644             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3645             n41 = n4 + 3;
3646             n15 = n1 + 3;
3647             n45 = n5 + 3;
3648           }
3649           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3650                                       nextNod[n4], prevNod[n4], prevNod[n5],
3651                                       midlNod[n1], nextNod[n41],
3652                                       midlNod[n4], prevNod[n41],
3653                                       prevNod[n15], nextNod[n15],
3654                                       nextNod[n45], prevNod[n45]);
3655         }
3656         else if(nbSame==2) {
3657           // 2d order tetrahedron of 10 nodes
3658           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3659           //                                 int n12,int n23,int n31,
3660           //                                 int n14,int n24,int n34, int ID);
3661           int n1 = iNotSameNode;
3662           int n2,n3,n12,n23,n31;
3663           if(i0>0) { // reversed case
3664             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3665             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3666             n12 = n2 + 3;
3667             n23 = n3 + 3;
3668             n31 = n1 + 3;
3669           }
3670           else {
3671             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3672             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3673             n12 = n1 + 3;
3674             n23 = n2 + 3;
3675             n31 = n3 + 3;
3676           }
3677           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3678                                        prevNod[n12], prevNod[n23], prevNod[n31],
3679                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3680         }
3681         break;
3682       }
3683       case 8: { // quadratic quadrangle
3684         if(nbSame==0) {
3685           // create hexahedron with 20 nodes
3686           if(i0>0) { // reversed case
3687             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3688                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3689                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3690                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3691                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3692           }
3693           else { // not reversed case
3694             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3695                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3696                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3697                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3698                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3699           }
3700         }
3701         else if(nbSame==1) { 
3702           // --- pyramid + pentahedron - can not be created since it is needed 
3703           // additional middle node ot the center of face
3704           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3705           return;
3706         }
3707         else if(nbSame==2) {
3708           // 2d order Pentahedron with 15 nodes
3709           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3710           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3711           //                                 int n14,int n25,int n36, int ID);
3712           int n1,n2,n4,n5;
3713           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3714             // iBeforeSame is same too
3715             n1 = iBeforeSame;
3716             n2 = iOpposSame;
3717             n4 = iSameNode;
3718             n5 = iAfterSame;
3719           }
3720           else {
3721             // iAfterSame is same too
3722             n1 = iSameNode;
3723             n2 = iBeforeSame;
3724             n4 = iAfterSame;
3725             n5 = iOpposSame;
3726           }
3727           int n12,n45,n14,n25;
3728           if(i0>0) { //reversed case
3729             n12 = n1 + 4;
3730             n45 = n5 + 4;
3731             n14 = n4 + 4;
3732             n25 = n2 + 4;
3733           }
3734           else {
3735             n12 = n2 + 4;
3736             n45 = n4 + 4;
3737             n14 = n1 + 4;
3738             n25 = n5 + 4;
3739           }
3740           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3741                                        prevNod[n4], prevNod[n5], nextNod[n5],
3742                                        prevNod[n12], midlNod[n2], nextNod[n12],
3743                                        prevNod[n45], midlNod[n5], nextNod[n45],
3744                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3745         }
3746         break;
3747       }
3748       default: {
3749         // realized for extrusion only
3750         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3751         //vector<int> quantities (nbNodes + 2);
3752
3753         //quantities[0] = nbNodes; // bottom of prism
3754         //for (int inode = 0; inode < nbNodes; inode++) {
3755         //  polyedre_nodes[inode] = prevNod[inode];
3756         //}
3757
3758         //quantities[1] = nbNodes; // top of prism
3759         //for (int inode = 0; inode < nbNodes; inode++) {
3760         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3761         //}
3762
3763         //for (int iface = 0; iface < nbNodes; iface++) {
3764         //  quantities[iface + 2] = 4;
3765         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3766         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3767         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3768         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3769         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3770         //}
3771         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3772         break;
3773       }
3774       }
3775     }
3776
3777     if(!aNewElem) {
3778       // realized for extrusion only
3779       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3780       vector<int> quantities (nbNodes + 2);
3781
3782       quantities[0] = nbNodes; // bottom of prism
3783       for (int inode = 0; inode < nbNodes; inode++) {
3784         polyedre_nodes[inode] = prevNod[inode];
3785       }
3786
3787       quantities[1] = nbNodes; // top of prism
3788       for (int inode = 0; inode < nbNodes; inode++) {
3789         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3790       }
3791
3792       for (int iface = 0; iface < nbNodes; iface++) {
3793         quantities[iface + 2] = 4;
3794         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3795         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3796         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3797         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3798         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3799       }
3800       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3801     }
3802
3803     if ( aNewElem ) {
3804       newElems.push_back( aNewElem );
3805       myLastCreatedElems.Append(aNewElem);
3806       srcElements.Append( elem );
3807       lastElem = aNewElem;
3808     }
3809
3810     // set new prev nodes
3811     for ( iNode = 0; iNode < nbNodes; iNode++ )
3812       prevNod[ iNode ] = nextNod[ iNode ];
3813
3814   } // for steps
3815 }
3816
3817 //=======================================================================
3818 /*!
3819  * \brief Create 1D and 2D elements around swept elements
3820  * \param mapNewNodes - source nodes and ones generated from them
3821  * \param newElemsMap - source elements and ones generated from them
3822  * \param elemNewNodesMap - nodes generated from each node of each element
3823  * \param elemSet - all swept elements
3824  * \param nbSteps - number of sweeping steps
3825  * \param srcElements - to append elem for each generated element
3826  */
3827 //=======================================================================
3828
3829 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3830                                   TElemOfElemListMap &     newElemsMap,
3831                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3832                                   TIDSortedElemSet&        elemSet,
3833                                   const int                nbSteps,
3834                                   SMESH_SequenceOfElemPtr& srcElements)
3835 {
3836   MESSAGE("makeWalls");
3837   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3838   SMESHDS_Mesh* aMesh = GetMeshDS();
3839
3840   // Find nodes belonging to only one initial element - sweep them to get edges.
3841
3842   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3843   for ( ; nList != mapNewNodes.end(); nList++ ) {
3844     const SMDS_MeshNode* node =
3845       static_cast<const SMDS_MeshNode*>( nList->first );
3846     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3847     int nbInitElems = 0;
3848     const SMDS_MeshElement* el = 0;
3849     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3850     while ( eIt->more() && nbInitElems < 2 ) {
3851       el = eIt->next();
3852       SMDSAbs_ElementType type = el->GetType();
3853       if ( type == SMDSAbs_Volume || type < highType ) continue;
3854       if ( type > highType ) {
3855         nbInitElems = 0;
3856         highType = type;
3857       }
3858       if ( elemSet.find(el) != elemSet.end() )
3859         nbInitElems++;
3860     }
3861     if ( nbInitElems < 2 ) {
3862       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3863       if(!NotCreateEdge) {
3864         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3865         list<const SMDS_MeshElement*> newEdges;
3866         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3867       }
3868     }
3869   }
3870
3871   // Make a ceiling for each element ie an equal element of last new nodes.
3872   // Find free links of faces - make edges and sweep them into faces.
3873
3874   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3875   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3876   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3877     const SMDS_MeshElement* elem = itElem->first;
3878     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3879
3880     if(itElem->second.size()==0) continue;
3881
3882     if ( elem->GetType() == SMDSAbs_Edge ) {
3883       // create a ceiling edge
3884       if (!elem->IsQuadratic()) {
3885         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3886                                vecNewNodes[ 1 ]->second.back())) {
3887           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3888                                                    vecNewNodes[ 1 ]->second.back()));
3889           srcElements.Append( myLastCreatedElems.Last() );
3890         }
3891       }
3892       else {
3893         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3894                                vecNewNodes[ 1 ]->second.back(),
3895                                vecNewNodes[ 2 ]->second.back())) {
3896           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3897                                                    vecNewNodes[ 1 ]->second.back(),
3898                                                    vecNewNodes[ 2 ]->second.back()));
3899           srcElements.Append( myLastCreatedElems.Last() );
3900         }
3901       }
3902     }
3903     if ( elem->GetType() != SMDSAbs_Face )
3904       continue;
3905
3906     bool hasFreeLinks = false;
3907
3908     TIDSortedElemSet avoidSet;
3909     avoidSet.insert( elem );
3910
3911     set<const SMDS_MeshNode*> aFaceLastNodes;
3912     int iNode, nbNodes = vecNewNodes.size();
3913     if(!elem->IsQuadratic()) {
3914       // loop on the face nodes
3915       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3916         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3917         // look for free links of the face
3918         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3919         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3920         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3921         // check if a link is free
3922         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3923           hasFreeLinks = true;
3924           // make an edge and a ceiling for a new edge
3925           if ( !aMesh->FindEdge( n1, n2 )) {
3926             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3927             srcElements.Append( myLastCreatedElems.Last() );
3928           }
3929           n1 = vecNewNodes[ iNode ]->second.back();
3930           n2 = vecNewNodes[ iNext ]->second.back();
3931           if ( !aMesh->FindEdge( n1, n2 )) {
3932             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3933             srcElements.Append( myLastCreatedElems.Last() );
3934           }
3935         }
3936       }
3937     }
3938     else { // elem is quadratic face
3939       int nbn = nbNodes/2;
3940       for ( iNode = 0; iNode < nbn; iNode++ ) {
3941         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3942         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3943         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3944         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3945         // check if a link is free
3946         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3947           hasFreeLinks = true;
3948           // make an edge and a ceiling for a new edge
3949           // find medium node
3950           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3951           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3952             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3953             srcElements.Append( myLastCreatedElems.Last() );
3954           }
3955           n1 = vecNewNodes[ iNode ]->second.back();
3956           n2 = vecNewNodes[ iNext ]->second.back();
3957           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3958           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3959             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3960             srcElements.Append( myLastCreatedElems.Last() );
3961           }
3962         }
3963       }
3964       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3965         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3966       }
3967     }
3968
3969     // sweep free links into faces
3970
3971     if ( hasFreeLinks )  {
3972       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3973       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3974
3975       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3976       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3977         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3978         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3979       }
3980       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3981         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3982         iVol = 0;
3983         while ( iVol++ < volNb ) v++;
3984         // find indices of free faces of a volume and their source edges
3985         list< int > freeInd;
3986         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3987         SMDS_VolumeTool vTool( *v );
3988         int iF, nbF = vTool.NbFaces();
3989         for ( iF = 0; iF < nbF; iF ++ ) {
3990           if (vTool.IsFreeFace( iF ) &&
3991               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3992               initNodeSet != faceNodeSet) // except an initial face
3993           {
3994             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3995               continue;
3996             freeInd.push_back( iF );
3997             // find source edge of a free face iF
3998             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3999             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4000             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4001                                    initNodeSet.begin(), initNodeSet.end(),
4002                                    commonNodes.begin());
4003             if ( (*v)->IsQuadratic() )
4004               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4005             else
4006               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4007 #ifdef _DEBUG_
4008             if ( !srcEdges.back() )
4009             {
4010               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4011                    << iF << " of volume #" << vTool.ID() << endl;
4012             }
4013 #endif
4014           }
4015         }
4016         if ( freeInd.empty() )
4017           continue;
4018
4019         // create faces for all steps;
4020         // if such a face has been already created by sweep of edge,
4021         // assure that its orientation is OK
4022         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
4023           vTool.Set( *v );
4024           vTool.SetExternalNormal();
4025           const int nextShift = vTool.IsForward() ? +1 : -1;
4026           list< int >::iterator ind = freeInd.begin();
4027           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4028           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4029           {
4030             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4031             int nbn = vTool.NbFaceNodes( *ind );
4032             if ( ! (*v)->IsPoly() )
4033               switch ( nbn ) {
4034               case 3: { ///// triangle
4035                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4036                 if ( !f ||
4037                      nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4038                 {
4039                   const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4040                                                        nodes[ 1 ],
4041                                                        nodes[ 1 + nextShift ] };
4042                   if ( f )
4043                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4044                   else
4045                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4046                                                               newOrder[ 2 ] ));
4047                 }
4048                 break;
4049               }
4050               case 4: { ///// quadrangle
4051                 const SMDS_MeshFace * f =
4052                   aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4053                 if ( !f ||
4054                      nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4055                 {
4056                   const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4057                                                        nodes[ 2 ], nodes[ 2+nextShift ] };
4058                   if ( f )
4059                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4060                   else
4061                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4062                                                               newOrder[ 2 ], newOrder[ 3 ]));
4063                 }
4064                 break;
4065               }
4066               case 6: { /////// quadratic triangle
4067                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4068                                                            nodes[1], nodes[3], nodes[5] );
4069                 if ( !f ||
4070                      nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4071                 {
4072                   const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4073                                                        nodes[2],
4074                                                        nodes[2 + 2*nextShift],
4075                                                        nodes[3 - 2*nextShift],
4076                                                        nodes[3],
4077                                                        nodes[3 + 2*nextShift]};
4078                   if ( f )
4079                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4080                   else
4081                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4082                                                               newOrder[ 1 ],
4083                                                               newOrder[ 2 ],
4084                                                               newOrder[ 3 ],
4085                                                               newOrder[ 4 ],
4086                                                               newOrder[ 5 ] ));
4087                 }
4088                 break;
4089               }
4090               default:       /////// quadratic quadrangle
4091                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4092                                                            nodes[1], nodes[3], nodes[5], nodes[7] );
4093                 if ( !f ||
4094                      nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4095                 {
4096                   const SMDS_MeshNode* newOrder[8] = { nodes[0],
4097                                                        nodes[4 - 2*nextShift],
4098                                                        nodes[4],
4099                                                        nodes[4 + 2*nextShift],
4100                                                        nodes[1],
4101                                                        nodes[5 - 2*nextShift],
4102                                                        nodes[5],
4103                                                        nodes[5 + 2*nextShift] };
4104                   if ( f )
4105                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4106                   else
4107                     myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4108                                                              newOrder[ 2 ], newOrder[ 3 ],
4109                                                              newOrder[ 4 ], newOrder[ 5 ],
4110                                                              newOrder[ 6 ], newOrder[ 7 ]));
4111                 }
4112               } // switch ( nbn )
4113
4114             else { //////// polygon
4115
4116               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4117               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4118               if ( !f ||
4119                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4120               {
4121                 if ( !vTool.IsForward() )
4122                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4123                 if ( f )
4124                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4125                 else
4126                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4127               }
4128             }
4129
4130             while ( srcElements.Length() < myLastCreatedElems.Length() )
4131               srcElements.Append( *srcEdge );
4132
4133           }  // loop on free faces
4134
4135           // go to the next volume
4136           iVol = 0;
4137           while ( iVol++ < nbVolumesByStep ) v++;
4138
4139         } // loop on steps
4140       } // loop on volumes of one step
4141     } // sweep free links into faces
4142
4143     // Make a ceiling face with a normal external to a volume
4144
4145     SMDS_VolumeTool lastVol( itElem->second.back() );
4146
4147     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4148     if ( iF >= 0 ) {
4149       lastVol.SetExternalNormal();
4150       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4151       int nbn = lastVol.NbFaceNodes( iF );
4152       switch ( nbn ) {
4153       case 3:
4154         if (!hasFreeLinks ||
4155             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4156           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4157         break;
4158       case 4:
4159         if (!hasFreeLinks ||
4160             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4161           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4162         break;
4163       default:
4164         if(itElem->second.back()->IsQuadratic()) {
4165           if(nbn==6) {
4166             if (!hasFreeLinks ||
4167                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4168                                  nodes[1], nodes[3], nodes[5]) ) {
4169               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4170                                                        nodes[1], nodes[3], nodes[5]));
4171             }
4172           }
4173           else { // nbn==8
4174             if (!hasFreeLinks ||
4175                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4176                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4177               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4178                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4179           }
4180         }
4181         else {
4182           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4183           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4184             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4185         }
4186       } // switch
4187
4188       while ( srcElements.Length() < myLastCreatedElems.Length() )
4189         srcElements.Append( myLastCreatedElems.Last() );
4190     }
4191   } // loop on swept elements
4192 }
4193
4194 //=======================================================================
4195 //function : RotationSweep
4196 //purpose  :
4197 //=======================================================================
4198
4199 SMESH_MeshEditor::PGroupIDs
4200 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4201                                 const gp_Ax1&      theAxis,
4202                                 const double       theAngle,
4203                                 const int          theNbSteps,
4204                                 const double       theTol,
4205                                 const bool         theMakeGroups,
4206                                 const bool         theMakeWalls)
4207 {
4208   myLastCreatedElems.Clear();
4209   myLastCreatedNodes.Clear();
4210
4211   // source elements for each generated one
4212   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4213
4214   MESSAGE( "RotationSweep()");
4215   gp_Trsf aTrsf;
4216   aTrsf.SetRotation( theAxis, theAngle );
4217   gp_Trsf aTrsf2;
4218   aTrsf2.SetRotation( theAxis, theAngle/2. );
4219
4220   gp_Lin aLine( theAxis );
4221   double aSqTol = theTol * theTol;
4222
4223   SMESHDS_Mesh* aMesh = GetMeshDS();
4224
4225   TNodeOfNodeListMap mapNewNodes;
4226   TElemOfVecOfNnlmiMap mapElemNewNodes;
4227   TElemOfElemListMap newElemsMap;
4228
4229   // loop on theElems
4230   TIDSortedElemSet::iterator itElem;
4231   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4232     const SMDS_MeshElement* elem = *itElem;
4233     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4234       continue;
4235     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4236     newNodesItVec.reserve( elem->NbNodes() );
4237
4238     // loop on elem nodes
4239     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4240     while ( itN->more() ) {
4241       // check if a node has been already sweeped
4242       const SMDS_MeshNode* node = cast2Node( itN->next() );
4243
4244       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4245       double coord[3];
4246       aXYZ.Coord( coord[0], coord[1], coord[2] );
4247       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4248
4249       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4250       if ( nIt == mapNewNodes.end() ) {
4251         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4252         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4253
4254         // make new nodes
4255         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4256         //double coord[3];
4257         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4258         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4259         const SMDS_MeshNode * newNode = node;
4260         for ( int i = 0; i < theNbSteps; i++ ) {
4261           if ( !isOnAxis ) {
4262             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4263               // create two nodes
4264               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4265               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4266               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4267               myLastCreatedNodes.Append(newNode);
4268               srcNodes.Append( node );
4269               listNewNodes.push_back( newNode );
4270               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4271               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4272             }
4273             else {
4274               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4275             }
4276             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4277             myLastCreatedNodes.Append(newNode);
4278             srcNodes.Append( node );
4279             listNewNodes.push_back( newNode );
4280           }
4281           else {
4282             listNewNodes.push_back( newNode );
4283             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4284               listNewNodes.push_back( newNode );
4285             }
4286           }
4287         }
4288       }
4289       /*
4290         else {
4291         // if current elem is quadratic and current node is not medium
4292         // we have to check - may be it is needed to insert additional nodes
4293         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4294         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4295         if(listNewNodes.size()==theNbSteps) {
4296         listNewNodes.clear();
4297         // make new nodes
4298         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4299         //double coord[3];
4300         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4301         const SMDS_MeshNode * newNode = node;
4302         if ( !isOnAxis ) {
4303         for(int i = 0; i<theNbSteps; i++) {
4304         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4305         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4306         cout<<"    3 AddNode:  "<<newNode;
4307         myLastCreatedNodes.Append(newNode);
4308         listNewNodes.push_back( newNode );
4309         srcNodes.Append( node );
4310         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4311         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4312         cout<<"    4 AddNode:  "<<newNode;
4313         myLastCreatedNodes.Append(newNode);
4314         srcNodes.Append( node );
4315         listNewNodes.push_back( newNode );
4316         }
4317         }
4318         else {
4319         listNewNodes.push_back( newNode );
4320         }
4321         }
4322         }
4323         }
4324       */
4325       newNodesItVec.push_back( nIt );
4326     }
4327     // make new elements
4328     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4329   }
4330
4331   if ( theMakeWalls )
4332     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4333
4334   PGroupIDs newGroupIDs;
4335   if ( theMakeGroups )
4336     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4337
4338   return newGroupIDs;
4339 }
4340
4341
4342 //=======================================================================
4343 //function : CreateNode
4344 //purpose  :
4345 //=======================================================================
4346 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4347                                                   const double y,
4348                                                   const double z,
4349                                                   const double tolnode,
4350                                                   SMESH_SequenceOfNode& aNodes)
4351 {
4352   myLastCreatedElems.Clear();
4353   myLastCreatedNodes.Clear();
4354
4355   gp_Pnt P1(x,y,z);
4356   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4357
4358   // try to search in sequence of existing nodes
4359   // if aNodes.Length()>0 we 'nave to use given sequence
4360   // else - use all nodes of mesh
4361   if(aNodes.Length()>0) {
4362     int i;
4363     for(i=1; i<=aNodes.Length(); i++) {
4364       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4365       if(P1.Distance(P2)<tolnode)
4366         return aNodes.Value(i);
4367     }
4368   }
4369   else {
4370     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4371     while(itn->more()) {
4372       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4373       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4374       if(P1.Distance(P2)<tolnode)
4375         return aN;
4376     }
4377   }
4378
4379   // create new node and return it
4380   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4381   myLastCreatedNodes.Append(NewNode);
4382   return NewNode;
4383 }
4384
4385
4386 //=======================================================================
4387 //function : ExtrusionSweep
4388 //purpose  :
4389 //=======================================================================
4390
4391 SMESH_MeshEditor::PGroupIDs
4392 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4393                                   const gp_Vec&       theStep,
4394                                   const int           theNbSteps,
4395                                   TElemOfElemListMap& newElemsMap,
4396                                   const bool          theMakeGroups,
4397                                   const int           theFlags,
4398                                   const double        theTolerance)
4399 {
4400   ExtrusParam aParams;
4401   aParams.myDir = gp_Dir(theStep);
4402   aParams.myNodes.Clear();
4403   aParams.mySteps = new TColStd_HSequenceOfReal;
4404   int i;
4405   for(i=1; i<=theNbSteps; i++)
4406     aParams.mySteps->Append(theStep.Magnitude());
4407
4408   return
4409     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4410 }
4411
4412
4413 //=======================================================================
4414 //function : ExtrusionSweep
4415 //purpose  :
4416 //=======================================================================
4417
4418 SMESH_MeshEditor::PGroupIDs
4419 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4420                                   ExtrusParam&        theParams,
4421                                   TElemOfElemListMap& newElemsMap,
4422                                   const bool          theMakeGroups,
4423                                   const int           theFlags,
4424                                   const double        theTolerance)
4425 {
4426   MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4427   myLastCreatedElems.Clear();
4428   myLastCreatedNodes.Clear();
4429
4430   // source elements for each generated one
4431   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4432
4433   SMESHDS_Mesh* aMesh = GetMeshDS();
4434
4435   int nbsteps = theParams.mySteps->Length();
4436
4437   TNodeOfNodeListMap mapNewNodes;
4438   //TNodeOfNodeVecMap mapNewNodes;
4439   TElemOfVecOfNnlmiMap mapElemNewNodes;
4440   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4441
4442   // loop on theElems
4443   TIDSortedElemSet::iterator itElem;
4444   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4445     // check element type
4446     const SMDS_MeshElement* elem = *itElem;
4447     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4448       continue;
4449
4450     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4451     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4452     newNodesItVec.reserve( elem->NbNodes() );
4453
4454     // loop on elem nodes
4455     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4456     while ( itN->more() )
4457     {
4458       // check if a node has been already sweeped
4459       const SMDS_MeshNode* node = cast2Node( itN->next() );
4460       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4461       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4462       if ( nIt == mapNewNodes.end() ) {
4463         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4464         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4465         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4466         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4467         //vecNewNodes.reserve(nbsteps);
4468
4469         // make new nodes
4470         double coord[] = { node->X(), node->Y(), node->Z() };
4471         //int nbsteps = theParams.mySteps->Length();
4472         for ( int i = 0; i < nbsteps; i++ ) {
4473           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4474             // create additional node
4475             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4476             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4477             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4478             if( theFlags & EXTRUSION_FLAG_SEW ) {
4479               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4480                                                          theTolerance, theParams.myNodes);
4481               listNewNodes.push_back( newNode );
4482             }
4483             else {
4484               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4485               myLastCreatedNodes.Append(newNode);
4486               srcNodes.Append( node );
4487               listNewNodes.push_back( newNode );
4488             }
4489           }
4490           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4491           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4492           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4493           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4494           if( theFlags & EXTRUSION_FLAG_SEW ) {
4495             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4496                                                        theTolerance, theParams.myNodes);
4497             listNewNodes.push_back( newNode );
4498             //vecNewNodes[i]=newNode;
4499           }
4500           else {
4501             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4502             myLastCreatedNodes.Append(newNode);
4503             srcNodes.Append( node );
4504             listNewNodes.push_back( newNode );
4505             //vecNewNodes[i]=newNode;
4506           }
4507         }
4508       }
4509       else {
4510         // if current elem is quadratic and current node is not medium
4511         // we have to check - may be it is needed to insert additional nodes
4512         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4513           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4514           if(listNewNodes.size()==nbsteps) {
4515             listNewNodes.clear();
4516             double coord[] = { node->X(), node->Y(), node->Z() };
4517             for ( int i = 0; i < nbsteps; i++ ) {
4518               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4519               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4520               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4521               if( theFlags & EXTRUSION_FLAG_SEW ) {
4522                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4523                                                            theTolerance, theParams.myNodes);
4524                 listNewNodes.push_back( newNode );
4525               }
4526               else {
4527                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4528                 myLastCreatedNodes.Append(newNode);
4529                 srcNodes.Append( node );
4530                 listNewNodes.push_back( newNode );
4531               }
4532               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4533               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4534               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4535               if( theFlags & EXTRUSION_FLAG_SEW ) {
4536                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4537                                                            theTolerance, theParams.myNodes);
4538                 listNewNodes.push_back( newNode );
4539               }
4540               else {
4541                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4542                 myLastCreatedNodes.Append(newNode);
4543                 srcNodes.Append( node );
4544                 listNewNodes.push_back( newNode );
4545               }
4546             }
4547           }
4548         }
4549       }
4550       newNodesItVec.push_back( nIt );
4551     }
4552     // make new elements
4553     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4554   }
4555
4556   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4557     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4558   }
4559   PGroupIDs newGroupIDs;
4560   if ( theMakeGroups )
4561     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4562
4563   return newGroupIDs;
4564 }
4565
4566 /*
4567 //=======================================================================
4568 //class    : SMESH_MeshEditor_PathPoint
4569 //purpose  : auxiliary class
4570 //=======================================================================
4571 class SMESH_MeshEditor_PathPoint {
4572 public:
4573 SMESH_MeshEditor_PathPoint() {
4574 myPnt.SetCoord(99., 99., 99.);
4575 myTgt.SetCoord(1.,0.,0.);
4576 myAngle=0.;
4577 myPrm=0.;
4578 }
4579 void SetPnt(const gp_Pnt& aP3D){
4580 myPnt=aP3D;
4581 }
4582 void SetTangent(const gp_Dir& aTgt){
4583 myTgt=aTgt;
4584 }
4585 void SetAngle(const double& aBeta){
4586 myAngle=aBeta;
4587 }
4588 void SetParameter(const double& aPrm){
4589 myPrm=aPrm;
4590 }
4591 const gp_Pnt& Pnt()const{
4592 return myPnt;
4593 }
4594 const gp_Dir& Tangent()const{
4595 return myTgt;
4596 }
4597 double Angle()const{
4598 return myAngle;
4599 }
4600 double Parameter()const{
4601 return myPrm;
4602 }
4603
4604 protected:
4605 gp_Pnt myPnt;
4606 gp_Dir myTgt;
4607 double myAngle;
4608 double myPrm;
4609 };
4610 */
4611
4612 //=======================================================================
4613 //function : ExtrusionAlongTrack
4614 //purpose  :
4615 //=======================================================================
4616 SMESH_MeshEditor::Extrusion_Error
4617 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4618                                        SMESH_subMesh*       theTrack,
4619                                        const SMDS_MeshNode* theN1,
4620                                        const bool           theHasAngles,
4621                                        list<double>&        theAngles,
4622                                        const bool           theLinearVariation,
4623                                        const bool           theHasRefPoint,
4624                                        const gp_Pnt&        theRefPoint,
4625                                        const bool           theMakeGroups)
4626 {
4627   MESSAGE("ExtrusionAlongTrack");
4628   myLastCreatedElems.Clear();
4629   myLastCreatedNodes.Clear();
4630
4631   int aNbE;
4632   std::list<double> aPrms;
4633   TIDSortedElemSet::iterator itElem;
4634
4635   gp_XYZ aGC;
4636   TopoDS_Edge aTrackEdge;
4637   TopoDS_Vertex aV1, aV2;
4638
4639   SMDS_ElemIteratorPtr aItE;
4640   SMDS_NodeIteratorPtr aItN;
4641   SMDSAbs_ElementType aTypeE;
4642
4643   TNodeOfNodeListMap mapNewNodes;
4644
4645   // 1. Check data
4646   aNbE = theElements.size();
4647   // nothing to do
4648   if ( !aNbE )
4649     return EXTR_NO_ELEMENTS;
4650
4651   // 1.1 Track Pattern
4652   ASSERT( theTrack );
4653
4654   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4655
4656   aItE = pSubMeshDS->GetElements();
4657   while ( aItE->more() ) {
4658     const SMDS_MeshElement* pE = aItE->next();
4659     aTypeE = pE->GetType();
4660     // Pattern must contain links only
4661     if ( aTypeE != SMDSAbs_Edge )
4662       return EXTR_PATH_NOT_EDGE;
4663   }
4664
4665   list<SMESH_MeshEditor_PathPoint> fullList;
4666
4667   const TopoDS_Shape& aS = theTrack->GetSubShape();
4668   // Sub shape for the Pattern must be an Edge or Wire
4669   if( aS.ShapeType() == TopAbs_EDGE ) {
4670     aTrackEdge = TopoDS::Edge( aS );
4671     // the Edge must not be degenerated
4672     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4673       return EXTR_BAD_PATH_SHAPE;
4674     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4675     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4676     const SMDS_MeshNode* aN1 = aItN->next();
4677     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4678     const SMDS_MeshNode* aN2 = aItN->next();
4679     // starting node must be aN1 or aN2
4680     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4681       return EXTR_BAD_STARTING_NODE;
4682     aItN = pSubMeshDS->GetNodes();
4683     while ( aItN->more() ) {
4684       const SMDS_MeshNode* pNode = aItN->next();
4685       const SMDS_EdgePosition* pEPos =
4686         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4687       double aT = pEPos->GetUParameter();
4688       aPrms.push_back( aT );
4689     }
4690     //Extrusion_Error err =
4691     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4692   }
4693   else if( aS.ShapeType() == TopAbs_WIRE ) {
4694     list< SMESH_subMesh* > LSM;
4695     TopTools_SequenceOfShape Edges;
4696     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4697     while(itSM->more()) {
4698       SMESH_subMesh* SM = itSM->next();
4699       LSM.push_back(SM);
4700       const TopoDS_Shape& aS = SM->GetSubShape();
4701       Edges.Append(aS);
4702     }
4703     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4704     int startNid = theN1->GetID();
4705     TColStd_MapOfInteger UsedNums;
4706     int NbEdges = Edges.Length();
4707     int i = 1;
4708     for(; i<=NbEdges; i++) {
4709       int k = 0;
4710       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4711       for(; itLSM!=LSM.end(); itLSM++) {
4712         k++;
4713         if(UsedNums.Contains(k)) continue;
4714         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4715         SMESH_subMesh* locTrack = *itLSM;
4716         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4717         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4718         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4719         const SMDS_MeshNode* aN1 = aItN->next();
4720         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4721         const SMDS_MeshNode* aN2 = aItN->next();
4722         // starting node must be aN1 or aN2
4723         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4724         // 2. Collect parameters on the track edge
4725         aPrms.clear();
4726         aItN = locMeshDS->GetNodes();
4727         while ( aItN->more() ) {
4728           const SMDS_MeshNode* pNode = aItN->next();
4729           const SMDS_EdgePosition* pEPos =
4730             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4731           double aT = pEPos->GetUParameter();
4732           aPrms.push_back( aT );
4733         }
4734         list<SMESH_MeshEditor_PathPoint> LPP;
4735         //Extrusion_Error err =
4736         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4737         LLPPs.push_back(LPP);
4738         UsedNums.Add(k);
4739         // update startN for search following egde
4740         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4741         else startNid = aN1->GetID();
4742         break;
4743       }
4744     }
4745     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4746     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4747     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4748     for(; itPP!=firstList.end(); itPP++) {
4749       fullList.push_back( *itPP );
4750     }
4751     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4752     fullList.pop_back();
4753     itLLPP++;
4754     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4755       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4756       itPP = currList.begin();
4757       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4758       gp_Dir D1 = PP1.Tangent();
4759       gp_Dir D2 = PP2.Tangent();
4760       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4761                            (D1.Z()+D2.Z())/2 ) );
4762       PP1.SetTangent(Dnew);
4763       fullList.push_back(PP1);
4764       itPP++;
4765       for(; itPP!=firstList.end(); itPP++) {
4766         fullList.push_back( *itPP );
4767       }
4768       PP1 = fullList.back();
4769       fullList.pop_back();
4770     }
4771     // if wire not closed
4772     fullList.push_back(PP1);
4773     // else ???
4774   }
4775   else {
4776     return EXTR_BAD_PATH_SHAPE;
4777   }
4778
4779   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4780                           theHasRefPoint, theRefPoint, theMakeGroups);
4781 }
4782
4783
4784 //=======================================================================
4785 //function : ExtrusionAlongTrack
4786 //purpose  :
4787 //=======================================================================
4788 SMESH_MeshEditor::Extrusion_Error
4789 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4790                                        SMESH_Mesh*          theTrack,
4791                                        const SMDS_MeshNode* theN1,
4792                                        const bool           theHasAngles,
4793                                        list<double>&        theAngles,
4794                                        const bool           theLinearVariation,
4795                                        const bool           theHasRefPoint,
4796                                        const gp_Pnt&        theRefPoint,
4797                                        const bool           theMakeGroups)
4798 {
4799   myLastCreatedElems.Clear();
4800   myLastCreatedNodes.Clear();
4801
4802   int aNbE;
4803   std::list<double> aPrms;
4804   TIDSortedElemSet::iterator itElem;
4805
4806   gp_XYZ aGC;
4807   TopoDS_Edge aTrackEdge;
4808   TopoDS_Vertex aV1, aV2;
4809
4810   SMDS_ElemIteratorPtr aItE;
4811   SMDS_NodeIteratorPtr aItN;
4812   SMDSAbs_ElementType aTypeE;
4813
4814   TNodeOfNodeListMap mapNewNodes;
4815
4816   // 1. Check data
4817   aNbE = theElements.size();
4818   // nothing to do
4819   if ( !aNbE )
4820     return EXTR_NO_ELEMENTS;
4821
4822   // 1.1 Track Pattern
4823   ASSERT( theTrack );
4824
4825   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4826
4827   aItE = pMeshDS->elementsIterator();
4828   while ( aItE->more() ) {
4829     const SMDS_MeshElement* pE = aItE->next();
4830     aTypeE = pE->GetType();
4831     // Pattern must contain links only
4832     if ( aTypeE != SMDSAbs_Edge )
4833       return EXTR_PATH_NOT_EDGE;
4834   }
4835
4836   list<SMESH_MeshEditor_PathPoint> fullList;
4837
4838   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4839   // Sub shape for the Pattern must be an Edge or Wire
4840   if( aS.ShapeType() == TopAbs_EDGE ) {
4841     aTrackEdge = TopoDS::Edge( aS );
4842     // the Edge must not be degenerated
4843     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4844       return EXTR_BAD_PATH_SHAPE;
4845     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4846     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4847     const SMDS_MeshNode* aN1 = aItN->next();
4848     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4849     const SMDS_MeshNode* aN2 = aItN->next();
4850     // starting node must be aN1 or aN2
4851     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4852       return EXTR_BAD_STARTING_NODE;
4853     aItN = pMeshDS->nodesIterator();
4854     while ( aItN->more() ) {
4855       const SMDS_MeshNode* pNode = aItN->next();
4856       if( pNode==aN1 || pNode==aN2 ) continue;
4857       const SMDS_EdgePosition* pEPos =
4858         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4859       double aT = pEPos->GetUParameter();
4860       aPrms.push_back( aT );
4861     }
4862     //Extrusion_Error err =
4863     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4864   }
4865   else if( aS.ShapeType() == TopAbs_WIRE ) {
4866     list< SMESH_subMesh* > LSM;
4867     TopTools_SequenceOfShape Edges;
4868     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4869     for(; eExp.More(); eExp.Next()) {
4870       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4871       if( BRep_Tool::Degenerated(E) ) continue;
4872       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4873       if(SM) {
4874         LSM.push_back(SM);
4875         Edges.Append(E);
4876       }
4877     }
4878     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4879     int startNid = theN1->GetID();
4880     TColStd_MapOfInteger UsedNums;
4881     int NbEdges = Edges.Length();
4882     int i = 1;
4883     for(; i<=NbEdges; i++) {
4884       int k = 0;
4885       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4886       for(; itLSM!=LSM.end(); itLSM++) {
4887         k++;
4888         if(UsedNums.Contains(k)) continue;
4889         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4890         SMESH_subMesh* locTrack = *itLSM;
4891         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4892         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4893         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4894         const SMDS_MeshNode* aN1 = aItN->next();
4895         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4896         const SMDS_MeshNode* aN2 = aItN->next();
4897         // starting node must be aN1 or aN2
4898         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4899         // 2. Collect parameters on the track edge
4900         aPrms.clear();
4901         aItN = locMeshDS->GetNodes();
4902         while ( aItN->more() ) {
4903           const SMDS_MeshNode* pNode = aItN->next();
4904           const SMDS_EdgePosition* pEPos =
4905             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4906           double aT = pEPos->GetUParameter();
4907           aPrms.push_back( aT );
4908         }
4909         list<SMESH_MeshEditor_PathPoint> LPP;
4910         //Extrusion_Error err =
4911         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4912         LLPPs.push_back(LPP);
4913         UsedNums.Add(k);
4914         // update startN for search following egde
4915         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4916         else startNid = aN1->GetID();
4917         break;
4918       }
4919     }
4920     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4921     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4922     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4923     for(; itPP!=firstList.end(); itPP++) {
4924       fullList.push_back( *itPP );
4925     }
4926     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4927     fullList.pop_back();
4928     itLLPP++;
4929     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4930       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4931       itPP = currList.begin();
4932       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4933       gp_Dir D1 = PP1.Tangent();
4934       gp_Dir D2 = PP2.Tangent();
4935       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4936                            (D1.Z()+D2.Z())/2 ) );
4937       PP1.SetTangent(Dnew);
4938       fullList.push_back(PP1);
4939       itPP++;
4940       for(; itPP!=currList.end(); itPP++) {
4941         fullList.push_back( *itPP );
4942       }
4943       PP1 = fullList.back();
4944       fullList.pop_back();
4945     }
4946     // if wire not closed
4947     fullList.push_back(PP1);
4948     // else ???
4949   }
4950   else {
4951     return EXTR_BAD_PATH_SHAPE;
4952   }
4953
4954   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4955                           theHasRefPoint, theRefPoint, theMakeGroups);
4956 }
4957
4958
4959 //=======================================================================
4960 //function : MakeEdgePathPoints
4961 //purpose  : auxilary for ExtrusionAlongTrack
4962 //=======================================================================
4963 SMESH_MeshEditor::Extrusion_Error
4964 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4965                                      const TopoDS_Edge& aTrackEdge,
4966                                      bool FirstIsStart,
4967                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4968 {
4969   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4970   aTolVec=1.e-7;
4971   aTolVec2=aTolVec*aTolVec;
4972   double aT1, aT2;
4973   TopoDS_Vertex aV1, aV2;
4974   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4975   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4976   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4977   // 2. Collect parameters on the track edge
4978   aPrms.push_front( aT1 );
4979   aPrms.push_back( aT2 );
4980   // sort parameters
4981   aPrms.sort();
4982   if( FirstIsStart ) {
4983     if ( aT1 > aT2 ) {
4984       aPrms.reverse();
4985     }
4986   }
4987   else {
4988     if ( aT2 > aT1 ) {
4989       aPrms.reverse();
4990     }
4991   }
4992   // 3. Path Points
4993   SMESH_MeshEditor_PathPoint aPP;
4994   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4995   std::list<double>::iterator aItD = aPrms.begin();
4996   for(; aItD != aPrms.end(); ++aItD) {
4997     double aT = *aItD;
4998     gp_Pnt aP3D;
4999     gp_Vec aVec;
5000     aC3D->D1( aT, aP3D, aVec );
5001     aL2 = aVec.SquareMagnitude();
5002     if ( aL2 < aTolVec2 )
5003       return EXTR_CANT_GET_TANGENT;
5004     gp_Dir aTgt( aVec );
5005     aPP.SetPnt( aP3D );
5006     aPP.SetTangent( aTgt );
5007     aPP.SetParameter( aT );
5008     LPP.push_back(aPP);
5009   }
5010   return EXTR_OK;
5011 }
5012
5013
5014 //=======================================================================
5015 //function : MakeExtrElements
5016 //purpose  : auxilary for ExtrusionAlongTrack
5017 //=======================================================================
5018 SMESH_MeshEditor::Extrusion_Error
5019 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5020                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5021                                    const bool theHasAngles,
5022                                    list<double>& theAngles,
5023                                    const bool theLinearVariation,
5024                                    const bool theHasRefPoint,
5025                                    const gp_Pnt& theRefPoint,
5026                                    const bool theMakeGroups)
5027 {
5028   MESSAGE("MakeExtrElements");
5029   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5030   int aNbTP = fullList.size();
5031   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5032   // Angles
5033   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5034     LinearAngleVariation(aNbTP-1, theAngles);
5035   }
5036   vector<double> aAngles( aNbTP );
5037   int j = 0;
5038   for(; j<aNbTP; ++j) {
5039     aAngles[j] = 0.;
5040   }
5041   if ( theHasAngles ) {
5042     double anAngle;;
5043     std::list<double>::iterator aItD = theAngles.begin();
5044     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5045       anAngle = *aItD;
5046       aAngles[j] = anAngle;
5047     }
5048   }
5049   // fill vector of path points with angles
5050   //aPPs.resize(fullList.size());
5051   j = -1;
5052   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5053   for(; itPP!=fullList.end(); itPP++) {
5054     j++;
5055     SMESH_MeshEditor_PathPoint PP = *itPP;
5056     PP.SetAngle(aAngles[j]);
5057     aPPs[j] = PP;
5058   }
5059
5060   TNodeOfNodeListMap mapNewNodes;
5061   TElemOfVecOfNnlmiMap mapElemNewNodes;
5062   TElemOfElemListMap newElemsMap;
5063   TIDSortedElemSet::iterator itElem;
5064   double aX, aY, aZ;
5065   int aNb;
5066   SMDSAbs_ElementType aTypeE;
5067   // source elements for each generated one
5068   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5069
5070   // 3. Center of rotation aV0
5071   gp_Pnt aV0 = theRefPoint;
5072   gp_XYZ aGC;
5073   if ( !theHasRefPoint ) {
5074     aNb = 0;
5075     aGC.SetCoord( 0.,0.,0. );
5076
5077     itElem = theElements.begin();
5078     for ( ; itElem != theElements.end(); itElem++ ) {
5079       const SMDS_MeshElement* elem = *itElem;
5080
5081       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5082       while ( itN->more() ) {
5083         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5084         aX = node->X();
5085         aY = node->Y();
5086         aZ = node->Z();
5087
5088         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5089           list<const SMDS_MeshNode*> aLNx;
5090           mapNewNodes[node] = aLNx;
5091           //
5092           gp_XYZ aXYZ( aX, aY, aZ );
5093           aGC += aXYZ;
5094           ++aNb;
5095         }
5096       }
5097     }
5098     aGC /= aNb;
5099     aV0.SetXYZ( aGC );
5100   } // if (!theHasRefPoint) {
5101   mapNewNodes.clear();
5102
5103   // 4. Processing the elements
5104   SMESHDS_Mesh* aMesh = GetMeshDS();
5105
5106   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5107     // check element type
5108     const SMDS_MeshElement* elem = *itElem;
5109     aTypeE = elem->GetType();
5110     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5111       continue;
5112
5113     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5114     newNodesItVec.reserve( elem->NbNodes() );
5115
5116     // loop on elem nodes
5117     int nodeIndex = -1;
5118     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5119     while ( itN->more() )
5120     {
5121       ++nodeIndex;
5122       // check if a node has been already processed
5123       const SMDS_MeshNode* node =
5124         static_cast<const SMDS_MeshNode*>( itN->next() );
5125       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5126       if ( nIt == mapNewNodes.end() ) {
5127         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5128         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5129
5130         // make new nodes
5131         aX = node->X();  aY = node->Y(); aZ = node->Z();
5132
5133         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5134         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5135         gp_Ax1 anAx1, anAxT1T0;
5136         gp_Dir aDT1x, aDT0x, aDT1T0;
5137
5138         aTolAng=1.e-4;
5139
5140         aV0x = aV0;
5141         aPN0.SetCoord(aX, aY, aZ);
5142
5143         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5144         aP0x = aPP0.Pnt();
5145         aDT0x= aPP0.Tangent();
5146         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5147
5148         for ( j = 1; j < aNbTP; ++j ) {
5149           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5150           aP1x = aPP1.Pnt();
5151           aDT1x = aPP1.Tangent();
5152           aAngle1x = aPP1.Angle();
5153
5154           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5155           // Translation
5156           gp_Vec aV01x( aP0x, aP1x );
5157           aTrsf.SetTranslation( aV01x );
5158
5159           // traslated point
5160           aV1x = aV0x.Transformed( aTrsf );
5161           aPN1 = aPN0.Transformed( aTrsf );
5162
5163           // rotation 1 [ T1,T0 ]
5164           aAngleT1T0=-aDT1x.Angle( aDT0x );
5165           if (fabs(aAngleT1T0) > aTolAng) {
5166             aDT1T0=aDT1x^aDT0x;
5167             anAxT1T0.SetLocation( aV1x );
5168             anAxT1T0.SetDirection( aDT1T0 );
5169             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5170
5171             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5172           }
5173
5174           // rotation 2
5175           if ( theHasAngles ) {
5176             anAx1.SetLocation( aV1x );
5177             anAx1.SetDirection( aDT1x );
5178             aTrsfRot.SetRotation( anAx1, aAngle1x );
5179
5180             aPN1 = aPN1.Transformed( aTrsfRot );
5181           }
5182
5183           // make new node
5184           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5185           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5186             // create additional node
5187             double x = ( aPN1.X() + aPN0.X() )/2.;
5188             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5189             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5190             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5191             myLastCreatedNodes.Append(newNode);
5192             srcNodes.Append( node );
5193             listNewNodes.push_back( newNode );
5194           }
5195           aX = aPN1.X();
5196           aY = aPN1.Y();
5197           aZ = aPN1.Z();
5198           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5199           myLastCreatedNodes.Append(newNode);
5200           srcNodes.Append( node );
5201           listNewNodes.push_back( newNode );
5202
5203           aPN0 = aPN1;
5204           aP0x = aP1x;
5205           aV0x = aV1x;
5206           aDT0x = aDT1x;
5207         }
5208       }
5209
5210       else {
5211         // if current elem is quadratic and current node is not medium
5212         // we have to check - may be it is needed to insert additional nodes
5213         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5214           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5215           if(listNewNodes.size()==aNbTP-1) {
5216             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5217             gp_XYZ P(node->X(), node->Y(), node->Z());
5218             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5219             int i;
5220             for(i=0; i<aNbTP-1; i++) {
5221               const SMDS_MeshNode* N = *it;
5222               double x = ( N->X() + P.X() )/2.;
5223               double y = ( N->Y() + P.Y() )/2.;
5224               double z = ( N->Z() + P.Z() )/2.;
5225               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5226               srcNodes.Append( node );
5227               myLastCreatedNodes.Append(newN);
5228               aNodes[2*i] = newN;
5229               aNodes[2*i+1] = N;
5230               P = gp_XYZ(N->X(),N->Y(),N->Z());
5231             }
5232             listNewNodes.clear();
5233             for(i=0; i<2*(aNbTP-1); i++) {
5234               listNewNodes.push_back(aNodes[i]);
5235             }
5236           }
5237         }
5238       }
5239
5240       newNodesItVec.push_back( nIt );
5241     }
5242     // make new elements
5243     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5244     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5245     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5246   }
5247
5248   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5249
5250   if ( theMakeGroups )
5251     generateGroups( srcNodes, srcElems, "extruded");
5252
5253   return EXTR_OK;
5254 }
5255
5256
5257 //=======================================================================
5258 //function : LinearAngleVariation
5259 //purpose  : auxilary for ExtrusionAlongTrack
5260 //=======================================================================
5261 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5262                                             list<double>& Angles)
5263 {
5264   int nbAngles = Angles.size();
5265   if( nbSteps > nbAngles ) {
5266     vector<double> theAngles(nbAngles);
5267     list<double>::iterator it = Angles.begin();
5268     int i = -1;
5269     for(; it!=Angles.end(); it++) {
5270       i++;
5271       theAngles[i] = (*it);
5272     }
5273     list<double> res;
5274     double rAn2St = double( nbAngles ) / double( nbSteps );
5275     double angPrev = 0, angle;
5276     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5277       double angCur = rAn2St * ( iSt+1 );
5278       double angCurFloor  = floor( angCur );
5279       double angPrevFloor = floor( angPrev );
5280       if ( angPrevFloor == angCurFloor )
5281         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5282       else {
5283         int iP = int( angPrevFloor );
5284         double angPrevCeil = ceil(angPrev);
5285         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5286
5287         int iC = int( angCurFloor );
5288         if ( iC < nbAngles )
5289           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5290
5291         iP = int( angPrevCeil );
5292         while ( iC-- > iP )
5293           angle += theAngles[ iC ];
5294       }
5295       res.push_back(angle);
5296       angPrev = angCur;
5297     }
5298     Angles.clear();
5299     it = res.begin();
5300     for(; it!=res.end(); it++)
5301       Angles.push_back( *it );
5302   }
5303 }
5304
5305
5306 //================================================================================
5307 /*!
5308  * \brief Move or copy theElements applying theTrsf to their nodes
5309  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5310  *  \param theTrsf - transformation to apply
5311  *  \param theCopy - if true, create translated copies of theElems
5312  *  \param theMakeGroups - if true and theCopy, create translated groups
5313  *  \param theTargetMesh - mesh to copy translated elements into
5314  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5315  */
5316 //================================================================================
5317
5318 SMESH_MeshEditor::PGroupIDs
5319 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5320                              const gp_Trsf&     theTrsf,
5321                              const bool         theCopy,
5322                              const bool         theMakeGroups,
5323                              SMESH_Mesh*        theTargetMesh)
5324 {
5325   myLastCreatedElems.Clear();
5326   myLastCreatedNodes.Clear();
5327
5328   bool needReverse = false;
5329   string groupPostfix;
5330   switch ( theTrsf.Form() ) {
5331   case gp_PntMirror:
5332     MESSAGE("gp_PntMirror");
5333     needReverse = true;
5334     groupPostfix = "mirrored";
5335     break;
5336   case gp_Ax1Mirror:
5337     MESSAGE("gp_Ax1Mirror");
5338     groupPostfix = "mirrored";
5339     break;
5340   case gp_Ax2Mirror:
5341     MESSAGE("gp_Ax2Mirror");
5342     needReverse = true;
5343     groupPostfix = "mirrored";
5344     break;
5345   case gp_Rotation:
5346     MESSAGE("gp_Rotation");
5347     groupPostfix = "rotated";
5348     break;
5349   case gp_Translation:
5350     MESSAGE("gp_Translation");
5351     groupPostfix = "translated";
5352     break;
5353   case gp_Scale:
5354     MESSAGE("gp_Scale");
5355     groupPostfix = "scaled";
5356     break;
5357   case gp_CompoundTrsf: // different scale by axis
5358     MESSAGE("gp_CompoundTrsf");
5359     groupPostfix = "scaled";
5360     break;
5361   default:
5362     MESSAGE("default");
5363     needReverse = false;
5364     groupPostfix = "transformed";
5365   }
5366
5367   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5368   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5369   SMESHDS_Mesh* aMesh    = GetMeshDS();
5370
5371
5372   // map old node to new one
5373   TNodeNodeMap nodeMap;
5374
5375   // elements sharing moved nodes; those of them which have all
5376   // nodes mirrored but are not in theElems are to be reversed
5377   TIDSortedElemSet inverseElemSet;
5378
5379   // source elements for each generated one
5380   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5381
5382   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5383   TIDSortedElemSet orphanNode;
5384
5385   if ( theElems.empty() ) // transform the whole mesh
5386   {
5387     // add all elements
5388     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5389     while ( eIt->more() ) theElems.insert( eIt->next() );
5390     // add orphan nodes
5391     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5392     while ( nIt->more() )
5393     {
5394       const SMDS_MeshNode* node = nIt->next();
5395       if ( node->NbInverseElements() == 0)
5396         orphanNode.insert( node );
5397     }
5398   }
5399
5400   // loop on elements to transform nodes : first orphan nodes then elems
5401   TIDSortedElemSet::iterator itElem;
5402   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5403   for (int i=0; i<2; i++)
5404   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5405     const SMDS_MeshElement* elem = *itElem;
5406     if ( !elem )
5407       continue;
5408
5409     // loop on elem nodes
5410     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5411     while ( itN->more() ) {
5412
5413       const SMDS_MeshNode* node = cast2Node( itN->next() );
5414       // check if a node has been already transformed
5415       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5416         nodeMap.insert( make_pair ( node, node ));
5417       if ( !n2n_isnew.second )
5418         continue;
5419
5420       double coord[3];
5421       coord[0] = node->X();
5422       coord[1] = node->Y();
5423       coord[2] = node->Z();
5424       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5425       if ( theTargetMesh ) {
5426         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5427         n2n_isnew.first->second = newNode;
5428         myLastCreatedNodes.Append(newNode);
5429         srcNodes.Append( node );
5430       }
5431       else if ( theCopy ) {
5432         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5433         n2n_isnew.first->second = newNode;
5434         myLastCreatedNodes.Append(newNode);
5435         srcNodes.Append( node );
5436       }
5437       else {
5438         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5439         // node position on shape becomes invalid
5440         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5441           ( SMDS_SpacePosition::originSpacePosition() );
5442       }
5443
5444       // keep inverse elements
5445       if ( !theCopy && !theTargetMesh && needReverse ) {
5446         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5447         while ( invElemIt->more() ) {
5448           const SMDS_MeshElement* iel = invElemIt->next();
5449           inverseElemSet.insert( iel );
5450         }
5451       }
5452     }
5453   }
5454
5455   // either create new elements or reverse mirrored ones
5456   if ( !theCopy && !needReverse && !theTargetMesh )
5457     return PGroupIDs();
5458
5459   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5460   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5461     theElems.insert( *invElemIt );
5462
5463   // replicate or reverse elements
5464   // TODO revoir ordre reverse vtk
5465   enum {
5466     REV_TETRA   = 0,  //  = nbNodes - 4
5467     REV_PYRAMID = 1,  //  = nbNodes - 4
5468     REV_PENTA   = 2,  //  = nbNodes - 4
5469     REV_FACE    = 3,
5470     REV_HEXA    = 4,  //  = nbNodes - 4
5471     FORWARD     = 5
5472   };
5473   int index[][8] = {
5474     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5475     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5476     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5477     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5478     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5479     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5480   };
5481
5482   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5483   {
5484     const SMDS_MeshElement* elem = *itElem;
5485     if ( !elem || elem->GetType() == SMDSAbs_Node )
5486       continue;
5487
5488     int nbNodes = elem->NbNodes();
5489     int elemType = elem->GetType();
5490
5491     if (elem->IsPoly()) {
5492       // Polygon or Polyhedral Volume
5493       switch ( elemType ) {
5494       case SMDSAbs_Face:
5495         {
5496           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5497           int iNode = 0;
5498           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5499           while (itN->more()) {
5500             const SMDS_MeshNode* node =
5501               static_cast<const SMDS_MeshNode*>(itN->next());
5502             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5503             if (nodeMapIt == nodeMap.end())
5504               break; // not all nodes transformed
5505             if (needReverse) {
5506               // reverse mirrored faces and volumes
5507               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5508             } else {
5509               poly_nodes[iNode] = (*nodeMapIt).second;
5510             }
5511             iNode++;
5512           }
5513           if ( iNode != nbNodes )
5514             continue; // not all nodes transformed
5515
5516           if ( theTargetMesh ) {
5517             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5518             srcElems.Append( elem );
5519           }
5520           else if ( theCopy ) {
5521             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5522             srcElems.Append( elem );
5523           }
5524           else {
5525             aMesh->ChangePolygonNodes(elem, poly_nodes);
5526           }
5527         }
5528         break;
5529       case SMDSAbs_Volume:
5530         {
5531           // ATTENTION: Reversing is not yet done!!!
5532           const SMDS_VtkVolume* aPolyedre =
5533             dynamic_cast<const SMDS_VtkVolume*>( elem );
5534           if (!aPolyedre) {
5535             MESSAGE("Warning: bad volumic element");
5536             continue;
5537           }
5538
5539           vector<const SMDS_MeshNode*> poly_nodes;
5540           vector<int> quantities;
5541
5542           bool allTransformed = true;
5543           int nbFaces = aPolyedre->NbFaces();
5544           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5545             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5546             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5547               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5548               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5549               if (nodeMapIt == nodeMap.end()) {
5550                 allTransformed = false; // not all nodes transformed
5551               } else {
5552                 poly_nodes.push_back((*nodeMapIt).second);
5553               }
5554             }
5555             quantities.push_back(nbFaceNodes);
5556           }
5557           if ( !allTransformed )
5558             continue; // not all nodes transformed
5559
5560           if ( theTargetMesh ) {
5561             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5562             srcElems.Append( elem );
5563           }
5564           else if ( theCopy ) {
5565             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5566             srcElems.Append( elem );
5567           }
5568           else {
5569             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5570           }
5571         }
5572         break;
5573       default:;
5574       }
5575       continue;
5576     }
5577
5578     // Regular elements
5579     int* i = index[ FORWARD ];
5580     if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5581       if ( elemType == SMDSAbs_Face )
5582         i = index[ REV_FACE ];
5583       else
5584         i = index[ nbNodes - 4 ];
5585     }
5586     if(elem->IsQuadratic()) {
5587       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5588       i = anIds;
5589       if(needReverse) {
5590         if(nbNodes==3) { // quadratic edge
5591           static int anIds[] = {1,0,2};
5592           i = anIds;
5593         }
5594         else if(nbNodes==6) { // quadratic triangle
5595           static int anIds[] = {0,2,1,5,4,3};
5596           i = anIds;
5597         }
5598         else if(nbNodes==8) { // quadratic quadrangle
5599           static int anIds[] = {0,3,2,1,7,6,5,4};
5600           i = anIds;
5601         }
5602         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5603           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5604           i = anIds;
5605         }
5606         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5607           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5608           i = anIds;
5609         }
5610         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5611           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5612           i = anIds;
5613         }
5614         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5615           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5616           i = anIds;
5617         }
5618       }
5619     }
5620
5621     // find transformed nodes
5622     vector<const SMDS_MeshNode*> nodes(nbNodes);
5623     int iNode = 0;
5624     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5625     while ( itN->more() ) {
5626       const SMDS_MeshNode* node =
5627         static_cast<const SMDS_MeshNode*>( itN->next() );
5628       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5629       if ( nodeMapIt == nodeMap.end() )
5630         break; // not all nodes transformed
5631       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5632     }
5633     if ( iNode != nbNodes )
5634       continue; // not all nodes transformed
5635
5636     if ( theTargetMesh ) {
5637       if ( SMDS_MeshElement* copy =
5638            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5639         myLastCreatedElems.Append( copy );
5640         srcElems.Append( elem );
5641       }
5642     }
5643     else if ( theCopy ) {
5644       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5645         srcElems.Append( elem );
5646     }
5647     else {
5648       // reverse element as it was reversed by transformation
5649       if ( nbNodes > 2 )
5650         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5651     }
5652   }
5653
5654   PGroupIDs newGroupIDs;
5655
5656   if ( ( theMakeGroups && theCopy ) ||
5657        ( theMakeGroups && theTargetMesh ) )
5658     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5659
5660   return newGroupIDs;
5661 }
5662
5663
5664 ////=======================================================================
5665 ////function : Scale
5666 ////purpose  :
5667 ////=======================================================================
5668 //
5669 //SMESH_MeshEditor::PGroupIDs
5670 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5671 //                         const gp_Pnt&            thePoint,
5672 //                         const std::list<double>& theScaleFact,
5673 //                         const bool         theCopy,
5674 //                         const bool         theMakeGroups,
5675 //                         SMESH_Mesh*        theTargetMesh)
5676 //{
5677 //  MESSAGE("Scale");
5678 //  myLastCreatedElems.Clear();
5679 //  myLastCreatedNodes.Clear();
5680 //
5681 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5682 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5683 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
5684 //
5685 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5686 //  std::list<double>::const_iterator itS = theScaleFact.begin();
5687 //  scaleX = (*itS);
5688 //  if(theScaleFact.size()==1) {
5689 //    scaleY = (*itS);
5690 //    scaleZ= (*itS);
5691 //  }
5692 //  if(theScaleFact.size()==2) {
5693 //    itS++;
5694 //    scaleY = (*itS);
5695 //    scaleZ= (*itS);
5696 //  }
5697 //  if(theScaleFact.size()>2) {
5698 //    itS++;
5699 //    scaleY = (*itS);
5700 //    itS++;
5701 //    scaleZ= (*itS);
5702 //  }
5703 //
5704 //  // map old node to new one
5705 //  TNodeNodeMap nodeMap;
5706 //
5707 //  // elements sharing moved nodes; those of them which have all
5708 //  // nodes mirrored but are not in theElems are to be reversed
5709 //  TIDSortedElemSet inverseElemSet;
5710 //
5711 //  // source elements for each generated one
5712 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
5713 //
5714 //  // loop on theElems
5715 //  TIDSortedElemSet::iterator itElem;
5716 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5717 //    const SMDS_MeshElement* elem = *itElem;
5718 //    if ( !elem )
5719 //      continue;
5720 //
5721 //    // loop on elem nodes
5722 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5723 //    while ( itN->more() ) {
5724 //
5725 //      // check if a node has been already transformed
5726 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
5727 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5728 //        nodeMap.insert( make_pair ( node, node ));
5729 //      if ( !n2n_isnew.second )
5730 //        continue;
5731 //
5732 //      //double coord[3];
5733 //      //coord[0] = node->X();
5734 //      //coord[1] = node->Y();
5735 //      //coord[2] = node->Z();
5736 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5737 //      double dx = (node->X() - thePoint.X()) * scaleX;
5738 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
5739 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
5740 //      if ( theTargetMesh ) {
5741 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5742 //        const SMDS_MeshNode * newNode =
5743 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5744 //        n2n_isnew.first->second = newNode;
5745 //        myLastCreatedNodes.Append(newNode);
5746 //        srcNodes.Append( node );
5747 //      }
5748 //      else if ( theCopy ) {
5749 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5750 //        const SMDS_MeshNode * newNode =
5751 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5752 //        n2n_isnew.first->second = newNode;
5753 //        myLastCreatedNodes.Append(newNode);
5754 //        srcNodes.Append( node );
5755 //      }
5756 //      else {
5757 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5758 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5759 //        // node position on shape becomes invalid
5760 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
5761 //          ( SMDS_SpacePosition::originSpacePosition() );
5762 //      }
5763 //
5764 //      // keep inverse elements
5765 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
5766 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5767 //      //  while ( invElemIt->more() ) {
5768 //      //    const SMDS_MeshElement* iel = invElemIt->next();
5769 //      //    inverseElemSet.insert( iel );
5770 //      //  }
5771 //      //}
5772 //    }
5773 //  }
5774 //
5775 //  // either create new elements or reverse mirrored ones
5776 //  //if ( !theCopy && !needReverse && !theTargetMesh )
5777 //  if ( !theCopy && !theTargetMesh )
5778 //    return PGroupIDs();
5779 //
5780 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5781 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5782 //    theElems.insert( *invElemIt );
5783 //
5784 //  // replicate or reverse elements
5785 //
5786 //  enum {
5787 //    REV_TETRA   = 0,  //  = nbNodes - 4
5788 //    REV_PYRAMID = 1,  //  = nbNodes - 4
5789 //    REV_PENTA   = 2,  //  = nbNodes - 4
5790 //    REV_FACE    = 3,
5791 //    REV_HEXA    = 4,  //  = nbNodes - 4
5792 //    FORWARD     = 5
5793 //  };
5794 //  int index[][8] = {
5795 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5796 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5797 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5798 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5799 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5800 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5801 //  };
5802 //
5803 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5804 //  {
5805 //    const SMDS_MeshElement* elem = *itElem;
5806 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
5807 //      continue;
5808 //
5809 //    int nbNodes = elem->NbNodes();
5810 //    int elemType = elem->GetType();
5811 //
5812 //    if (elem->IsPoly()) {
5813 //      // Polygon or Polyhedral Volume
5814 //      switch ( elemType ) {
5815 //      case SMDSAbs_Face:
5816 //        {
5817 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5818 //          int iNode = 0;
5819 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5820 //          while (itN->more()) {
5821 //            const SMDS_MeshNode* node =
5822 //              static_cast<const SMDS_MeshNode*>(itN->next());
5823 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5824 //            if (nodeMapIt == nodeMap.end())
5825 //              break; // not all nodes transformed
5826 //            //if (needReverse) {
5827 //            //  // reverse mirrored faces and volumes
5828 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5829 //            //} else {
5830 //            poly_nodes[iNode] = (*nodeMapIt).second;
5831 //            //}
5832 //            iNode++;
5833 //          }
5834 //          if ( iNode != nbNodes )
5835 //            continue; // not all nodes transformed
5836 //
5837 //          if ( theTargetMesh ) {
5838 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5839 //            srcElems.Append( elem );
5840 //          }
5841 //          else if ( theCopy ) {
5842 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5843 //            srcElems.Append( elem );
5844 //          }
5845 //          else {
5846 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
5847 //          }
5848 //        }
5849 //        break;
5850 //      case SMDSAbs_Volume:
5851 //        {
5852 //          // ATTENTION: Reversing is not yet done!!!
5853 //          const SMDS_VtkVolume* aPolyedre =
5854 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
5855 //          if (!aPolyedre) {
5856 //            MESSAGE("Warning: bad volumic element");
5857 //            continue;
5858 //          }
5859 //
5860 //          vector<const SMDS_MeshNode*> poly_nodes;
5861 //          vector<int> quantities;
5862 //
5863 //          bool allTransformed = true;
5864 //          int nbFaces = aPolyedre->NbFaces();
5865 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5866 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5867 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5868 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5869 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5870 //              if (nodeMapIt == nodeMap.end()) {
5871 //                allTransformed = false; // not all nodes transformed
5872 //              } else {
5873 //                poly_nodes.push_back((*nodeMapIt).second);
5874 //              }
5875 //            }
5876 //            quantities.push_back(nbFaceNodes);
5877 //          }
5878 //          if ( !allTransformed )
5879 //            continue; // not all nodes transformed
5880 //
5881 //          if ( theTargetMesh ) {
5882 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5883 //            srcElems.Append( elem );
5884 //          }
5885 //          else if ( theCopy ) {
5886 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5887 //            srcElems.Append( elem );
5888 //          }
5889 //          else {
5890 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5891 //          }
5892 //        }
5893 //        break;
5894 //      default:;
5895 //      }
5896 //      continue;
5897 //    }
5898 //
5899 //    // Regular elements
5900 //    int* i = index[ FORWARD ];
5901 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5902 //    //  if ( elemType == SMDSAbs_Face )
5903 //    //    i = index[ REV_FACE ];
5904 //    //  else
5905 //    //    i = index[ nbNodes - 4 ];
5906 //
5907 //    if(elem->IsQuadratic()) {
5908 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5909 //      i = anIds;
5910 //      //if(needReverse) {
5911 //      //  if(nbNodes==3) { // quadratic edge
5912 //      //    static int anIds[] = {1,0,2};
5913 //      //    i = anIds;
5914 //      //  }
5915 //      //  else if(nbNodes==6) { // quadratic triangle
5916 //      //    static int anIds[] = {0,2,1,5,4,3};
5917 //      //    i = anIds;
5918 //      //  }
5919 //      //  else if(nbNodes==8) { // quadratic quadrangle
5920 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
5921 //      //    i = anIds;
5922 //      //  }
5923 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5924 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5925 //      //    i = anIds;
5926 //      //  }
5927 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5928 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5929 //      //    i = anIds;
5930 //      //  }
5931 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5932 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5933 //      //    i = anIds;
5934 //      //  }
5935 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5936 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5937 //      //    i = anIds;
5938 //      //  }
5939 //      //}
5940 //    }
5941 //
5942 //    // find transformed nodes
5943 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
5944 //    int iNode = 0;
5945 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5946 //    while ( itN->more() ) {
5947 //      const SMDS_MeshNode* node =
5948 //        static_cast<const SMDS_MeshNode*>( itN->next() );
5949 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5950 //      if ( nodeMapIt == nodeMap.end() )
5951 //        break; // not all nodes transformed
5952 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5953 //    }
5954 //    if ( iNode != nbNodes )
5955 //      continue; // not all nodes transformed
5956 //
5957 //    if ( theTargetMesh ) {
5958 //      if ( SMDS_MeshElement* copy =
5959 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5960 //        myLastCreatedElems.Append( copy );
5961 //        srcElems.Append( elem );
5962 //      }
5963 //    }
5964 //    else if ( theCopy ) {
5965 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5966 //        myLastCreatedElems.Append( copy );
5967 //        srcElems.Append( elem );
5968 //      }
5969 //    }
5970 //    else {
5971 //      // reverse element as it was reversed by transformation
5972 //      if ( nbNodes > 2 )
5973 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5974 //    }
5975 //  }
5976 //
5977 //  PGroupIDs newGroupIDs;
5978 //
5979 //  if ( theMakeGroups && theCopy ||
5980 //       theMakeGroups && theTargetMesh ) {
5981 //    string groupPostfix = "scaled";
5982 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5983 //  }
5984 //
5985 //  return newGroupIDs;
5986 //}
5987
5988
5989 //=======================================================================
5990 /*!
5991  * \brief Create groups of elements made during transformation
5992  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5993  * \param elemGens - elements making corresponding myLastCreatedElems
5994  * \param postfix - to append to names of new groups
5995  */
5996 //=======================================================================
5997
5998 SMESH_MeshEditor::PGroupIDs
5999 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
6000                                  const SMESH_SequenceOfElemPtr& elemGens,
6001                                  const std::string&             postfix,
6002                                  SMESH_Mesh*                    targetMesh)
6003 {
6004   PGroupIDs newGroupIDs( new list<int> );
6005   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6006
6007   // Sort existing groups by types and collect their names
6008
6009   // to store an old group and a generated new one
6010   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6011   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6012   // group names
6013   set< string > groupNames;
6014   //
6015   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6016   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6017   while ( groupIt->more() ) {
6018     SMESH_Group * group = groupIt->next();
6019     if ( !group ) continue;
6020     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6021     if ( !groupDS || groupDS->IsEmpty() ) continue;
6022     groupNames.insert( group->GetName() );
6023     groupDS->SetStoreName( group->GetName() );
6024     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6025   }
6026
6027   // Groups creation
6028
6029   // loop on nodes and elements
6030   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6031   {
6032     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6033     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6034     if ( gens.Length() != elems.Length() )
6035       throw SALOME_Exception(LOCALIZED("invalid args"));
6036
6037     // loop on created elements
6038     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6039     {
6040       const SMDS_MeshElement* sourceElem = gens( iElem );
6041       if ( !sourceElem ) {
6042         MESSAGE("generateGroups(): NULL source element");
6043         continue;
6044       }
6045       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6046       if ( groupsOldNew.empty() ) {
6047         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6048           ++iElem; // skip all elements made by sourceElem
6049         continue;
6050       }
6051       // collect all elements made by sourceElem
6052       list< const SMDS_MeshElement* > resultElems;
6053       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6054         if ( resElem != sourceElem )
6055           resultElems.push_back( resElem );
6056       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6057         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6058           if ( resElem != sourceElem )
6059             resultElems.push_back( resElem );
6060       // do not generate element groups from node ones
6061       if ( sourceElem->GetType() == SMDSAbs_Node &&
6062            elems( iElem )->GetType() != SMDSAbs_Node )
6063         continue;
6064
6065       // add resultElems to groups made by ones the sourceElem belongs to
6066       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6067       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6068       {
6069         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6070         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6071         {
6072           SMDS_MeshGroup* & newGroup = gOldNew->second;
6073           if ( !newGroup )// create a new group
6074           {
6075             // make a name
6076             string name = oldGroup->GetStoreName();
6077             if ( !targetMesh ) {
6078               name += "_";
6079               name += postfix;
6080               int nb = 0;
6081               while ( !groupNames.insert( name ).second ) // name exists
6082               {
6083                 if ( nb == 0 ) {
6084                   name += "_1";
6085                 }
6086                 else {
6087                   TCollection_AsciiString nbStr(nb+1);
6088                   name.resize( name.rfind('_')+1 );
6089                   name += nbStr.ToCString();
6090                 }
6091                 ++nb;
6092               }
6093             }
6094             // make a group
6095             int id;
6096             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6097                                                  name.c_str(), id );
6098             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6099             newGroup = & groupDS->SMDSGroup();
6100             newGroupIDs->push_back( id );
6101           }
6102
6103           // fill in a new group
6104           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6105           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6106             newGroup->Add( *resElemIt );
6107         }
6108       }
6109     } // loop on created elements
6110   }// loop on nodes and elements
6111
6112   return newGroupIDs;
6113 }
6114
6115 //================================================================================
6116 /*!
6117  * \brief Return list of group of nodes close to each other within theTolerance
6118  *        Search among theNodes or in the whole mesh if theNodes is empty using
6119  *        an Octree algorithm
6120  */
6121 //================================================================================
6122
6123 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6124                                             const double         theTolerance,
6125                                             TListOfListOfNodes & theGroupsOfNodes)
6126 {
6127   myLastCreatedElems.Clear();
6128   myLastCreatedNodes.Clear();
6129
6130   if ( theNodes.empty() )
6131   { // get all nodes in the mesh
6132     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6133     while ( nIt->more() )
6134       theNodes.insert( theNodes.end(),nIt->next());
6135   }
6136
6137   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6138 }
6139
6140
6141 //=======================================================================
6142 /*!
6143  * \brief Implementation of search for the node closest to point
6144  */
6145 //=======================================================================
6146
6147 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6148 {
6149   //---------------------------------------------------------------------
6150   /*!
6151    * \brief Constructor
6152    */
6153   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6154   {
6155     myMesh = ( SMESHDS_Mesh* ) theMesh;
6156
6157     TIDSortedNodeSet nodes;
6158     if ( theMesh ) {
6159       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6160       while ( nIt->more() )
6161         nodes.insert( nodes.end(), nIt->next() );
6162     }
6163     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6164
6165     // get max size of a leaf box
6166     SMESH_OctreeNode* tree = myOctreeNode;
6167     while ( !tree->isLeaf() )
6168     {
6169       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6170       if ( cIt->more() )
6171         tree = cIt->next();
6172     }
6173     myHalfLeafSize = tree->maxSize() / 2.;
6174   }
6175
6176   //---------------------------------------------------------------------
6177   /*!
6178    * \brief Move node and update myOctreeNode accordingly
6179    */
6180   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6181   {
6182     myOctreeNode->UpdateByMoveNode( node, toPnt );
6183     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6184   }
6185
6186   //---------------------------------------------------------------------
6187   /*!
6188    * \brief Do it's job
6189    */
6190   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6191   {
6192     map<double, const SMDS_MeshNode*> dist2Nodes;
6193     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6194     if ( !dist2Nodes.empty() )
6195       return dist2Nodes.begin()->second;
6196     list<const SMDS_MeshNode*> nodes;
6197     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6198
6199     double minSqDist = DBL_MAX;
6200     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6201     {
6202       // sort leafs by their distance from thePnt
6203       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6204       TDistTreeMap treeMap;
6205       list< SMESH_OctreeNode* > treeList;
6206       list< SMESH_OctreeNode* >::iterator trIt;
6207       treeList.push_back( myOctreeNode );
6208
6209       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6210       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6211       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6212       {
6213         SMESH_OctreeNode* tree = *trIt;
6214         if ( !tree->isLeaf() ) // put children to the queue
6215         {
6216           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6217           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6218           while ( cIt->more() )
6219             treeList.push_back( cIt->next() );
6220         }
6221         else if ( tree->NbNodes() ) // put a tree to the treeMap
6222         {
6223           const Bnd_B3d& box = tree->getBox();
6224           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6225           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6226           if ( !it_in.second ) // not unique distance to box center
6227             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6228         }
6229       }
6230       // find distance after which there is no sense to check tree's
6231       double sqLimit = DBL_MAX;
6232       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6233       if ( treeMap.size() > 5 ) {
6234         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6235         const Bnd_B3d& box = closestTree->getBox();
6236         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6237         sqLimit = limit * limit;
6238       }
6239       // get all nodes from trees
6240       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6241         if ( sqDist_tree->first > sqLimit )
6242           break;
6243         SMESH_OctreeNode* tree = sqDist_tree->second;
6244         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6245       }
6246     }
6247     // find closest among nodes
6248     minSqDist = DBL_MAX;
6249     const SMDS_MeshNode* closestNode = 0;
6250     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6251     for ( ; nIt != nodes.end(); ++nIt ) {
6252       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6253       if ( minSqDist > sqDist ) {
6254         closestNode = *nIt;
6255         minSqDist = sqDist;
6256       }
6257     }
6258     return closestNode;
6259   }
6260
6261   //---------------------------------------------------------------------
6262   /*!
6263    * \brief Destructor
6264    */
6265   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6266
6267   //---------------------------------------------------------------------
6268   /*!
6269    * \brief Return the node tree
6270    */
6271   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6272
6273 private:
6274   SMESH_OctreeNode* myOctreeNode;
6275   SMESHDS_Mesh*     myMesh;
6276   double            myHalfLeafSize; // max size of a leaf box
6277 };
6278
6279 //=======================================================================
6280 /*!
6281  * \brief Return SMESH_NodeSearcher
6282  */
6283 //=======================================================================
6284
6285 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6286 {
6287   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6288 }
6289
6290 // ========================================================================
6291 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6292 {
6293   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6294   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6295   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6296
6297   //=======================================================================
6298   /*!
6299    * \brief Octal tree of bounding boxes of elements
6300    */
6301   //=======================================================================
6302
6303   class ElementBndBoxTree : public SMESH_Octree
6304   {
6305   public:
6306
6307     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6308     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6309     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6310     ~ElementBndBoxTree();
6311
6312   protected:
6313     ElementBndBoxTree() {}
6314     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6315     void buildChildrenData();
6316     Bnd_B3d* buildRootBox();
6317   private:
6318     //!< Bounding box of element
6319     struct ElementBox : public Bnd_B3d
6320     {
6321       const SMDS_MeshElement* _element;
6322       int                     _refCount; // an ElementBox can be included in several tree branches
6323       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6324     };
6325     vector< ElementBox* > _elements;
6326   };
6327
6328   //================================================================================
6329   /*!
6330    * \brief ElementBndBoxTree creation
6331    */
6332   //================================================================================
6333
6334   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6335     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6336   {
6337     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6338     _elements.reserve( nbElems );
6339
6340     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6341     while ( elemIt->more() )
6342       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6343
6344     if ( _elements.size() > MaxNbElemsInLeaf )
6345       compute();
6346     else
6347       myIsLeaf = true;
6348   }
6349
6350   //================================================================================
6351   /*!
6352    * \brief Destructor
6353    */
6354   //================================================================================
6355
6356   ElementBndBoxTree::~ElementBndBoxTree()
6357   {
6358     for ( int i = 0; i < _elements.size(); ++i )
6359       if ( --_elements[i]->_refCount <= 0 )
6360         delete _elements[i];
6361   }
6362
6363   //================================================================================
6364   /*!
6365    * \brief Return the maximal box
6366    */
6367   //================================================================================
6368
6369   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6370   {
6371     Bnd_B3d* box = new Bnd_B3d;
6372     for ( int i = 0; i < _elements.size(); ++i )
6373       box->Add( *_elements[i] );
6374     return box;
6375   }
6376
6377   //================================================================================
6378   /*!
6379    * \brief Redistrubute element boxes among children
6380    */
6381   //================================================================================
6382
6383   void ElementBndBoxTree::buildChildrenData()
6384   {
6385     for ( int i = 0; i < _elements.size(); ++i )
6386     {
6387       for (int j = 0; j < 8; j++)
6388       {
6389         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6390         {
6391           _elements[i]->_refCount++;
6392           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6393         }
6394       }
6395       _elements[i]->_refCount--;
6396     }
6397     _elements.clear();
6398
6399     for (int j = 0; j < 8; j++)
6400     {
6401       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6402       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6403         child->myIsLeaf = true;
6404
6405       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6406         child->_elements.resize( child->_elements.size() ); // compact
6407     }
6408   }
6409
6410   //================================================================================
6411   /*!
6412    * \brief Return elements which can include the point
6413    */
6414   //================================================================================
6415
6416   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6417                                                 TIDSortedElemSet& foundElems)
6418   {
6419     if ( level() && getBox().IsOut( point.XYZ() ))
6420       return;
6421
6422     if ( isLeaf() )
6423     {
6424       for ( int i = 0; i < _elements.size(); ++i )
6425         if ( !_elements[i]->IsOut( point.XYZ() ))
6426           foundElems.insert( _elements[i]->_element );
6427     }
6428     else
6429     {
6430       for (int i = 0; i < 8; i++)
6431         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6432     }
6433   }
6434
6435   //================================================================================
6436   /*!
6437    * \brief Return elements which can be intersected by the line
6438    */
6439   //================================================================================
6440
6441   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6442                                                TIDSortedElemSet& foundElems)
6443   {
6444     if ( level() && getBox().IsOut( line ))
6445       return;
6446
6447     if ( isLeaf() )
6448     {
6449       for ( int i = 0; i < _elements.size(); ++i )
6450         if ( !_elements[i]->IsOut( line ))
6451           foundElems.insert( _elements[i]->_element );
6452     }
6453     else
6454     {
6455       for (int i = 0; i < 8; i++)
6456         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6457     }
6458   }
6459
6460   //================================================================================
6461   /*!
6462    * \brief Construct the element box
6463    */
6464   //================================================================================
6465
6466   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6467   {
6468     _element  = elem;
6469     _refCount = 1;
6470     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6471     while ( nIt->more() )
6472       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6473     Enlarge( tolerance );
6474   }
6475
6476 } // namespace
6477
6478 //=======================================================================
6479 /*!
6480  * \brief Implementation of search for the elements by point and
6481  *        of classification of point in 2D mesh
6482  */
6483 //=======================================================================
6484
6485 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6486 {
6487   SMESHDS_Mesh*                _mesh;
6488   SMDS_ElemIteratorPtr         _meshPartIt;
6489   ElementBndBoxTree*           _ebbTree;
6490   SMESH_NodeSearcherImpl*      _nodeSearcher;
6491   SMDSAbs_ElementType          _elementType;
6492   double                       _tolerance;
6493   bool                         _outerFacesFound;
6494   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6495
6496   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6497     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6498   ~SMESH_ElementSearcherImpl()
6499   {
6500     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6501     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6502   }
6503   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6504                                   SMDSAbs_ElementType                type,
6505                                   vector< const SMDS_MeshElement* >& foundElements);
6506   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6507
6508   void GetElementsNearLine( const gp_Ax1&                      line,
6509                             SMDSAbs_ElementType                type,
6510                             vector< const SMDS_MeshElement* >& foundElems);
6511   double getTolerance();
6512   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6513                             const double tolerance, double & param);
6514   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6515   bool isOuterBoundary(const SMDS_MeshElement* face) const
6516   {
6517     return _outerFaces.empty() || _outerFaces.count(face);
6518   }
6519   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6520   {
6521     const SMDS_MeshElement* _face;
6522     gp_Vec                  _faceNorm;
6523     bool                    _coincides; //!< the line lays in face plane
6524     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6525       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6526   };
6527   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6528   {
6529     SMESH_TLink      _link;
6530     TIDSortedElemSet _faces;
6531     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6532       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6533   };
6534 };
6535
6536 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6537 {
6538   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6539              << ", _coincides="<<i._coincides << ")";
6540 }
6541
6542 //=======================================================================
6543 /*!
6544  * \brief define tolerance for search
6545  */
6546 //=======================================================================
6547
6548 double SMESH_ElementSearcherImpl::getTolerance()
6549 {
6550   if ( _tolerance < 0 )
6551   {
6552     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6553
6554     _tolerance = 0;
6555     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6556     {
6557       double boxSize = _nodeSearcher->getTree()->maxSize();
6558       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6559     }
6560     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6561     {
6562       double boxSize = _ebbTree->maxSize();
6563       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6564     }
6565     if ( _tolerance == 0 )
6566     {
6567       // define tolerance by size of a most complex element
6568       int complexType = SMDSAbs_Volume;
6569       while ( complexType > SMDSAbs_All &&
6570               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6571         --complexType;
6572       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6573       double elemSize;
6574       if ( complexType == int( SMDSAbs_Node ))
6575       {
6576         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6577         elemSize = 1;
6578         if ( meshInfo.NbNodes() > 2 )
6579           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6580       }
6581       else
6582       {
6583         SMDS_ElemIteratorPtr elemIt =
6584             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6585         const SMDS_MeshElement* elem = elemIt->next();
6586         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6587         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6588         elemSize = 0;
6589         while ( nodeIt->more() )
6590         {
6591           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6592           elemSize = max( dist, elemSize );
6593         }
6594       }
6595       _tolerance = 1e-4 * elemSize;
6596     }
6597   }
6598   return _tolerance;
6599 }
6600
6601 //================================================================================
6602 /*!
6603  * \brief Find intersection of the line and an edge of face and return parameter on line
6604  */
6605 //================================================================================
6606
6607 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6608                                                      const SMDS_MeshElement* face,
6609                                                      const double            tol,
6610                                                      double &                param)
6611 {
6612   int nbInts = 0;
6613   param = 0;
6614
6615   GeomAPI_ExtremaCurveCurve anExtCC;
6616   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6617   
6618   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6619   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6620   {
6621     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6622                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6623     anExtCC.Init( lineCurve, edge);
6624     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6625     {
6626       Quantity_Parameter pl, pe;
6627       anExtCC.LowerDistanceParameters( pl, pe );
6628       param += pl;
6629       if ( ++nbInts == 2 )
6630         break;
6631     }
6632   }
6633   if ( nbInts > 0 ) param /= nbInts;
6634   return nbInts > 0;
6635 }
6636 //================================================================================
6637 /*!
6638  * \brief Find all faces belonging to the outer boundary of mesh
6639  */
6640 //================================================================================
6641
6642 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6643 {
6644   if ( _outerFacesFound ) return;
6645
6646   // Collect all outer faces by passing from one outer face to another via their links
6647   // and BTW find out if there are internal faces at all.
6648
6649   // checked links and links where outer boundary meets internal one
6650   set< SMESH_TLink > visitedLinks, seamLinks;
6651
6652   // links to treat with already visited faces sharing them
6653   list < TFaceLink > startLinks;
6654
6655   // load startLinks with the first outerFace
6656   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6657   _outerFaces.insert( outerFace );
6658
6659   TIDSortedElemSet emptySet;
6660   while ( !startLinks.empty() )
6661   {
6662     const SMESH_TLink& link  = startLinks.front()._link;
6663     TIDSortedElemSet&  faces = startLinks.front()._faces;
6664
6665     outerFace = *faces.begin();
6666     // find other faces sharing the link
6667     const SMDS_MeshElement* f;
6668     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6669       faces.insert( f );
6670
6671     // select another outer face among the found 
6672     const SMDS_MeshElement* outerFace2 = 0;
6673     if ( faces.size() == 2 )
6674     {
6675       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6676     }
6677     else if ( faces.size() > 2 )
6678     {
6679       seamLinks.insert( link );
6680
6681       // link direction within the outerFace
6682       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6683                    SMESH_TNodeXYZ( link.node2()));
6684       int i1 = outerFace->GetNodeIndex( link.node1() );
6685       int i2 = outerFace->GetNodeIndex( link.node2() );
6686       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6687       if ( rev ) n1n2.Reverse();
6688       // outerFace normal
6689       gp_XYZ ofNorm, fNorm;
6690       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6691       {
6692         // direction from the link inside outerFace
6693         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6694         // sort all other faces by angle with the dirInOF
6695         map< double, const SMDS_MeshElement* > angle2Face;
6696         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6697         for ( ; face != faces.end(); ++face )
6698         {
6699           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6700             continue;
6701           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6702           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6703           if ( angle < 0 ) angle += 2*PI;
6704           angle2Face.insert( make_pair( angle, *face ));
6705         }
6706         if ( !angle2Face.empty() )
6707           outerFace2 = angle2Face.begin()->second;
6708       }
6709     }
6710     // store the found outer face and add its links to continue seaching from
6711     if ( outerFace2 )
6712     {
6713       _outerFaces.insert( outerFace );
6714       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6715       for ( int i = 0; i < nbNodes; ++i )
6716       {
6717         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6718         if ( visitedLinks.insert( link2 ).second )
6719           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6720       }
6721     }
6722     startLinks.pop_front();
6723   }
6724   _outerFacesFound = true;
6725
6726   if ( !seamLinks.empty() )
6727   {
6728     // There are internal boundaries touching the outher one,
6729     // find all faces of internal boundaries in order to find
6730     // faces of boundaries of holes, if any.
6731     
6732   }
6733   else
6734   {
6735     _outerFaces.clear();
6736   }
6737 }
6738
6739 //=======================================================================
6740 /*!
6741  * \brief Find elements of given type where the given point is IN or ON.
6742  *        Returns nb of found elements and elements them-selves.
6743  *
6744  * 'ALL' type means elements of any type excluding nodes and 0D elements
6745  */
6746 //=======================================================================
6747
6748 int SMESH_ElementSearcherImpl::
6749 FindElementsByPoint(const gp_Pnt&                      point,
6750                     SMDSAbs_ElementType                type,
6751                     vector< const SMDS_MeshElement* >& foundElements)
6752 {
6753   foundElements.clear();
6754
6755   double tolerance = getTolerance();
6756
6757   // =================================================================================
6758   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6759   {
6760     if ( !_nodeSearcher )
6761       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6762
6763     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6764     if ( !closeNode ) return foundElements.size();
6765
6766     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6767       return foundElements.size(); // to far from any node
6768
6769     if ( type == SMDSAbs_Node )
6770     {
6771       foundElements.push_back( closeNode );
6772     }
6773     else
6774     {
6775       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6776       while ( elemIt->more() )
6777         foundElements.push_back( elemIt->next() );
6778     }
6779   }
6780   // =================================================================================
6781   else // elements more complex than 0D
6782   {
6783     if ( !_ebbTree || _elementType != type )
6784     {
6785       if ( _ebbTree ) delete _ebbTree;
6786       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6787     }
6788     TIDSortedElemSet suspectElems;
6789     _ebbTree->getElementsNearPoint( point, suspectElems );
6790     TIDSortedElemSet::iterator elem = suspectElems.begin();
6791     for ( ; elem != suspectElems.end(); ++elem )
6792       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6793         foundElements.push_back( *elem );
6794   }
6795   return foundElements.size();
6796 }
6797
6798 //================================================================================
6799 /*!
6800  * \brief Classify the given point in the closed 2D mesh
6801  */
6802 //================================================================================
6803
6804 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6805 {
6806   double tolerance = getTolerance();
6807   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6808   {
6809     if ( _ebbTree ) delete _ebbTree;
6810     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6811   }
6812   // Algo: analyse transition of a line starting at the point through mesh boundary;
6813   // try three lines parallel to axis of the coordinate system and perform rough
6814   // analysis. If solution is not clear perform thorough analysis.
6815
6816   const int nbAxes = 3;
6817   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6818   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6819   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6820   multimap< int, int > nbInt2Axis; // to find the simplest case
6821   for ( int axis = 0; axis < nbAxes; ++axis )
6822   {
6823     gp_Ax1 lineAxis( point, axisDir[axis]);
6824     gp_Lin line    ( lineAxis );
6825
6826     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6827     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6828
6829     // Intersect faces with the line
6830
6831     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6832     TIDSortedElemSet::iterator face = suspectFaces.begin();
6833     for ( ; face != suspectFaces.end(); ++face )
6834     {
6835       // get face plane
6836       gp_XYZ fNorm;
6837       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6838       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6839
6840       // perform intersection
6841       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6842       if ( !intersection.IsDone() )
6843         continue;
6844       if ( intersection.IsInQuadric() )
6845       {
6846         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6847       }
6848       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6849       {
6850         gp_Pnt intersectionPoint = intersection.Point(1);
6851         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6852           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6853       }
6854     }
6855     // Analyse intersections roughly
6856
6857     int nbInter = u2inters.size();
6858     if ( nbInter == 0 )
6859       return TopAbs_OUT; 
6860
6861     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6862     if ( nbInter == 1 ) // not closed mesh
6863       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6864
6865     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6866       return TopAbs_ON;
6867
6868     if ( (f<0) == (l<0) )
6869       return TopAbs_OUT;
6870
6871     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6872     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6873     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6874       return TopAbs_IN;
6875
6876     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6877
6878     if ( _outerFacesFound ) break; // pass to thorough analysis
6879
6880   } // three attempts - loop on CS axes
6881
6882   // Analyse intersections thoroughly.
6883   // We make two loops maximum, on the first one we only exclude touching intersections,
6884   // on the second, if situation is still unclear, we gather and use information on
6885   // position of faces (internal or outer). If faces position is already gathered,
6886   // we make the second loop right away.
6887
6888   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6889   {
6890     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6891     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6892     {
6893       int axis = nb_axis->second;
6894       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6895
6896       gp_Ax1 lineAxis( point, axisDir[axis]);
6897       gp_Lin line    ( lineAxis );
6898
6899       // add tangent intersections to u2inters
6900       double param;
6901       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6902       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6903         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6904           u2inters.insert(make_pair( param, *tgtInt ));
6905       tangentInters[ axis ].clear();
6906
6907       // Count intersections before and after the point excluding touching ones.
6908       // If hasPositionInfo we count intersections of outer boundary only
6909
6910       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6911       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6912       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6913       bool ok = ! u_int1->second._coincides;
6914       while ( ok && u_int1 != u2inters.end() )
6915       {
6916         double u = u_int1->first;
6917         bool touchingInt = false;
6918         if ( ++u_int2 != u2inters.end() )
6919         {
6920           // skip intersections at the same point (if the line passes through edge or node)
6921           int nbSamePnt = 0;
6922           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6923           {
6924             ++nbSamePnt;
6925             ++u_int2;
6926           }
6927
6928           // skip tangent intersections
6929           int nbTgt = 0;
6930           const SMDS_MeshElement* prevFace = u_int1->second._face;
6931           while ( ok && u_int2->second._coincides )
6932           {
6933             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6934               ok = false;
6935             else
6936             {
6937               nbTgt++;
6938               u_int2++;
6939               ok = ( u_int2 != u2inters.end() );
6940             }
6941           }
6942           if ( !ok ) break;
6943
6944           // skip intersections at the same point after tangent intersections
6945           if ( nbTgt > 0 )
6946           {
6947             double u2 = u_int2->first;
6948             ++u_int2;
6949             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6950             {
6951               ++nbSamePnt;
6952               ++u_int2;
6953             }
6954           }
6955           // decide if we skipped a touching intersection
6956           if ( nbSamePnt + nbTgt > 0 )
6957           {
6958             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6959             map< double, TInters >::iterator u_int = u_int1;
6960             for ( ; u_int != u_int2; ++u_int )
6961             {
6962               if ( u_int->second._coincides ) continue;
6963               double dot = u_int->second._faceNorm * line.Direction();
6964               if ( dot > maxDot ) maxDot = dot;
6965               if ( dot < minDot ) minDot = dot;
6966             }
6967             touchingInt = ( minDot*maxDot < 0 );
6968           }
6969         }
6970         if ( !touchingInt )
6971         {
6972           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6973           {
6974             if ( u < 0 )
6975               ++nbIntBeforePoint;
6976             else
6977               ++nbIntAfterPoint;
6978           }
6979           if ( u < f ) f = u;
6980           if ( u > l ) l = u;
6981         }
6982
6983         u_int1 = u_int2; // to next intersection
6984
6985       } // loop on intersections with one line
6986
6987       if ( ok )
6988       {
6989         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6990           return TopAbs_ON;
6991
6992         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6993           return TopAbs_OUT; 
6994
6995         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6996           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6997
6998         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6999           return TopAbs_IN;
7000
7001         if ( (f<0) == (l<0) )
7002           return TopAbs_OUT;
7003
7004         if ( hasPositionInfo )
7005           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7006       }
7007     } // loop on intersections of the tree lines - thorough analysis
7008
7009     if ( !hasPositionInfo )
7010     {
7011       // gather info on faces position - is face in the outer boundary or not
7012       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7013       findOuterBoundary( u2inters.begin()->second._face );
7014     }
7015
7016   } // two attempts - with and w/o faces position info in the mesh
7017
7018   return TopAbs_UNKNOWN;
7019 }
7020
7021 //=======================================================================
7022 /*!
7023  * \brief Return elements possibly intersecting the line
7024  */
7025 //=======================================================================
7026
7027 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7028                                                      SMDSAbs_ElementType                type,
7029                                                      vector< const SMDS_MeshElement* >& foundElems)
7030 {
7031   if ( !_ebbTree || _elementType != type )
7032   {
7033     if ( _ebbTree ) delete _ebbTree;
7034     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7035   }
7036   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7037   _ebbTree->getElementsNearLine( line, suspectFaces );
7038   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7039 }
7040
7041 //=======================================================================
7042 /*!
7043  * \brief Return SMESH_ElementSearcher
7044  */
7045 //=======================================================================
7046
7047 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7048 {
7049   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7050 }
7051
7052 //=======================================================================
7053 /*!
7054  * \brief Return SMESH_ElementSearcher
7055  */
7056 //=======================================================================
7057
7058 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7059 {
7060   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7061 }
7062
7063 //=======================================================================
7064 /*!
7065  * \brief Return true if the point is IN or ON of the element
7066  */
7067 //=======================================================================
7068
7069 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7070 {
7071   if ( element->GetType() == SMDSAbs_Volume)
7072   {
7073     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7074   }
7075
7076   // get ordered nodes
7077
7078   vector< gp_XYZ > xyz;
7079   vector<const SMDS_MeshNode*> nodeList;
7080
7081   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7082   if ( element->IsQuadratic() ) {
7083     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7084       nodeIt = f->interlacedNodesElemIterator();
7085     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7086       nodeIt = e->interlacedNodesElemIterator();
7087   }
7088   while ( nodeIt->more() )
7089     {
7090       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7091       xyz.push_back( SMESH_TNodeXYZ(node) );
7092       nodeList.push_back(node);
7093     }
7094
7095   int i, nbNodes = element->NbNodes();
7096
7097   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7098   {
7099     // compute face normal
7100     gp_Vec faceNorm(0,0,0);
7101     xyz.push_back( xyz.front() );
7102     nodeList.push_back( nodeList.front() );
7103     for ( i = 0; i < nbNodes; ++i )
7104     {
7105       gp_Vec edge1( xyz[i+1], xyz[i]);
7106       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7107       faceNorm += edge1 ^ edge2;
7108     }
7109     double normSize = faceNorm.Magnitude();
7110     if ( normSize <= tol )
7111     {
7112       // degenerated face: point is out if it is out of all face edges
7113       for ( i = 0; i < nbNodes; ++i )
7114       {
7115         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7116         if ( !isOut( &edge, point, tol ))
7117           return false;
7118       }
7119       return true;
7120     }
7121     faceNorm /= normSize;
7122
7123     // check if the point lays on face plane
7124     gp_Vec n2p( xyz[0], point );
7125     if ( fabs( n2p * faceNorm ) > tol )
7126       return true; // not on face plane
7127
7128     // check if point is out of face boundary:
7129     // define it by closest transition of a ray point->infinity through face boundary
7130     // on the face plane.
7131     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7132     // to find intersections of the ray with the boundary.
7133     gp_Vec ray = n2p;
7134     gp_Vec plnNorm = ray ^ faceNorm;
7135     normSize = plnNorm.Magnitude();
7136     if ( normSize <= tol ) return false; // point coincides with the first node
7137     plnNorm /= normSize;
7138     // for each node of the face, compute its signed distance to the plane
7139     vector<double> dist( nbNodes + 1);
7140     for ( i = 0; i < nbNodes; ++i )
7141     {
7142       gp_Vec n2p( xyz[i], point );
7143       dist[i] = n2p * plnNorm;
7144     }
7145     dist.back() = dist.front();
7146     // find the closest intersection
7147     int    iClosest = -1;
7148     double rClosest, distClosest = 1e100;;
7149     gp_Pnt pClosest;
7150     for ( i = 0; i < nbNodes; ++i )
7151     {
7152       double r;
7153       if ( fabs( dist[i]) < tol )
7154         r = 0.;
7155       else if ( fabs( dist[i+1]) < tol )
7156         r = 1.;
7157       else if ( dist[i] * dist[i+1] < 0 )
7158         r = dist[i] / ( dist[i] - dist[i+1] );
7159       else
7160         continue; // no intersection
7161       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7162       gp_Vec p2int ( point, pInt);
7163       if ( p2int * ray > -tol ) // right half-space
7164       {
7165         double intDist = p2int.SquareMagnitude();
7166         if ( intDist < distClosest )
7167         {
7168           iClosest = i;
7169           rClosest = r;
7170           pClosest = pInt;
7171           distClosest = intDist;
7172         }
7173       }
7174     }
7175     if ( iClosest < 0 )
7176       return true; // no intesections - out
7177
7178     // analyse transition
7179     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7180     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7181     gp_Vec p2int ( point, pClosest );
7182     bool out = (edgeNorm * p2int) < -tol;
7183     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7184       return out;
7185
7186     // ray pass through a face node; analyze transition through an adjacent edge
7187     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7188     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7189     gp_Vec edgeAdjacent( p1, p2 );
7190     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7191     bool out2 = (edgeNorm2 * p2int) < -tol;
7192
7193     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7194     return covexCorner ? (out || out2) : (out && out2);
7195   }
7196   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7197   {
7198     // point is out of edge if it is NOT ON any straight part of edge
7199     // (we consider quadratic edge as being composed of two straight parts)
7200     for ( i = 1; i < nbNodes; ++i )
7201     {
7202       gp_Vec edge( xyz[i-1], xyz[i]);
7203       gp_Vec n1p ( xyz[i-1], point);
7204       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7205       if ( dist > tol )
7206         continue;
7207       gp_Vec n2p( xyz[i], point );
7208       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7209         continue;
7210       return false; // point is ON this part
7211     }
7212     return true;
7213   }
7214   // Node or 0D element -------------------------------------------------------------------------
7215   {
7216     gp_Vec n2p ( xyz[0], point );
7217     return n2p.Magnitude() <= tol;
7218   }
7219   return true;
7220 }
7221
7222 //=======================================================================
7223 //function : SimplifyFace
7224 //purpose  :
7225 //=======================================================================
7226 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7227                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7228                                     vector<int>&                        quantities) const
7229 {
7230   int nbNodes = faceNodes.size();
7231
7232   if (nbNodes < 3)
7233     return 0;
7234
7235   set<const SMDS_MeshNode*> nodeSet;
7236
7237   // get simple seq of nodes
7238   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7239   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7240   int iSimple = 0, nbUnique = 0;
7241
7242   simpleNodes[iSimple++] = faceNodes[0];
7243   nbUnique++;
7244   for (int iCur = 1; iCur < nbNodes; iCur++) {
7245     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7246       simpleNodes[iSimple++] = faceNodes[iCur];
7247       if (nodeSet.insert( faceNodes[iCur] ).second)
7248         nbUnique++;
7249     }
7250   }
7251   int nbSimple = iSimple;
7252   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7253     nbSimple--;
7254     iSimple--;
7255   }
7256
7257   if (nbUnique < 3)
7258     return 0;
7259
7260   // separate loops
7261   int nbNew = 0;
7262   bool foundLoop = (nbSimple > nbUnique);
7263   while (foundLoop) {
7264     foundLoop = false;
7265     set<const SMDS_MeshNode*> loopSet;
7266     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7267       const SMDS_MeshNode* n = simpleNodes[iSimple];
7268       if (!loopSet.insert( n ).second) {
7269         foundLoop = true;
7270
7271         // separate loop
7272         int iC = 0, curLast = iSimple;
7273         for (; iC < curLast; iC++) {
7274           if (simpleNodes[iC] == n) break;
7275         }
7276         int loopLen = curLast - iC;
7277         if (loopLen > 2) {
7278           // create sub-element
7279           nbNew++;
7280           quantities.push_back(loopLen);
7281           for (; iC < curLast; iC++) {
7282             poly_nodes.push_back(simpleNodes[iC]);
7283           }
7284         }
7285         // shift the rest nodes (place from the first loop position)
7286         for (iC = curLast + 1; iC < nbSimple; iC++) {
7287           simpleNodes[iC - loopLen] = simpleNodes[iC];
7288         }
7289         nbSimple -= loopLen;
7290         iSimple -= loopLen;
7291       }
7292     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7293   } // while (foundLoop)
7294
7295   if (iSimple > 2) {
7296     nbNew++;
7297     quantities.push_back(iSimple);
7298     for (int i = 0; i < iSimple; i++)
7299       poly_nodes.push_back(simpleNodes[i]);
7300   }
7301
7302   return nbNew;
7303 }
7304
7305 //=======================================================================
7306 //function : MergeNodes
7307 //purpose  : In each group, the cdr of nodes are substituted by the first one
7308 //           in all elements.
7309 //=======================================================================
7310
7311 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7312 {
7313   MESSAGE("MergeNodes");
7314   myLastCreatedElems.Clear();
7315   myLastCreatedNodes.Clear();
7316
7317   SMESHDS_Mesh* aMesh = GetMeshDS();
7318
7319   TNodeNodeMap nodeNodeMap; // node to replace - new node
7320   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7321   list< int > rmElemIds, rmNodeIds;
7322
7323   // Fill nodeNodeMap and elems
7324
7325   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7326   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7327     list<const SMDS_MeshNode*>& nodes = *grIt;
7328     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7329     const SMDS_MeshNode* nToKeep = *nIt;
7330     //MESSAGE("node to keep " << nToKeep->GetID());
7331     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7332       const SMDS_MeshNode* nToRemove = *nIt;
7333       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7334       if ( nToRemove != nToKeep ) {
7335         //MESSAGE("  node to remove " << nToRemove->GetID());
7336         rmNodeIds.push_back( nToRemove->GetID() );
7337         AddToSameGroups( nToKeep, nToRemove, aMesh );
7338       }
7339
7340       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7341       while ( invElemIt->more() ) {
7342         const SMDS_MeshElement* elem = invElemIt->next();
7343         elems.insert(elem);
7344       }
7345     }
7346   }
7347   // Change element nodes or remove an element
7348
7349   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7350   for ( ; eIt != elems.end(); eIt++ ) {
7351     const SMDS_MeshElement* elem = *eIt;
7352     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7353     int nbNodes = elem->NbNodes();
7354     int aShapeId = FindShape( elem );
7355
7356     set<const SMDS_MeshNode*> nodeSet;
7357     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7358     int iUnique = 0, iCur = 0, nbRepl = 0;
7359     vector<int> iRepl( nbNodes );
7360
7361     // get new seq of nodes
7362     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7363     while ( itN->more() ) {
7364       const SMDS_MeshNode* n =
7365         static_cast<const SMDS_MeshNode*>( itN->next() );
7366
7367       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7368       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7369         n = (*nnIt).second;
7370         // BUG 0020185: begin
7371         {
7372           bool stopRecur = false;
7373           set<const SMDS_MeshNode*> nodesRecur;
7374           nodesRecur.insert(n);
7375           while (!stopRecur) {
7376             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7377             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7378               n = (*nnIt_i).second;
7379               if (!nodesRecur.insert(n).second) {
7380                 // error: recursive dependancy
7381                 stopRecur = true;
7382               }
7383             }
7384             else
7385               stopRecur = true;
7386           }
7387         }
7388         // BUG 0020185: end
7389         iRepl[ nbRepl++ ] = iCur;
7390       }
7391       curNodes[ iCur ] = n;
7392       bool isUnique = nodeSet.insert( n ).second;
7393       if ( isUnique ) {
7394         uniqueNodes[ iUnique++ ] = n;
7395         if ( nbRepl && iRepl[ nbRepl-1 ] == iCur )
7396           --nbRepl; // n do not stick to a node of the elem
7397       }
7398       iCur++;
7399     }
7400
7401     // Analyse element topology after replacement
7402
7403     bool isOk = true;
7404     int nbUniqueNodes = nodeSet.size();
7405     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7406     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7407       // Polygons and Polyhedral volumes
7408       if (elem->IsPoly()) {
7409
7410         if (elem->GetType() == SMDSAbs_Face) {
7411           // Polygon
7412           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7413           int inode = 0;
7414           for (; inode < nbNodes; inode++) {
7415             face_nodes[inode] = curNodes[inode];
7416           }
7417
7418           vector<const SMDS_MeshNode *> polygons_nodes;
7419           vector<int> quantities;
7420           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7421           if (nbNew > 0) {
7422             inode = 0;
7423             for (int iface = 0; iface < nbNew; iface++) {
7424               int nbNodes = quantities[iface];
7425               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7426               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7427                 poly_nodes[ii] = polygons_nodes[inode];
7428               }
7429               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7430               myLastCreatedElems.Append(newElem);
7431               if (aShapeId)
7432                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7433             }
7434
7435             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7436             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7437             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7438             int quid =0;
7439             if (nbNew > 0) quid = nbNew - 1;
7440             vector<int> newquant(quantities.begin()+quid, quantities.end());
7441             const SMDS_MeshElement* newElem = 0;
7442             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7443             myLastCreatedElems.Append(newElem);
7444             if ( aShapeId && newElem )
7445               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7446             rmElemIds.push_back(elem->GetID());
7447           }
7448           else {
7449             rmElemIds.push_back(elem->GetID());
7450           }
7451
7452         }
7453         else if (elem->GetType() == SMDSAbs_Volume) {
7454           // Polyhedral volume
7455           if (nbUniqueNodes < 4) {
7456             rmElemIds.push_back(elem->GetID());
7457           }
7458           else {
7459             // each face has to be analyzed in order to check volume validity
7460             const SMDS_VtkVolume* aPolyedre =
7461               dynamic_cast<const SMDS_VtkVolume*>( elem );
7462             if (aPolyedre) {
7463               int nbFaces = aPolyedre->NbFaces();
7464
7465               vector<const SMDS_MeshNode *> poly_nodes;
7466               vector<int> quantities;
7467
7468               for (int iface = 1; iface <= nbFaces; iface++) {
7469                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7470                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7471
7472                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7473                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7474                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7475                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7476                     faceNode = (*nnIt).second;
7477                   }
7478                   faceNodes[inode - 1] = faceNode;
7479                 }
7480
7481                 SimplifyFace(faceNodes, poly_nodes, quantities);
7482               }
7483
7484               if (quantities.size() > 3) {
7485                 // to be done: remove coincident faces
7486               }
7487
7488               if (quantities.size() > 3)
7489                 {
7490                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7491                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7492                   const SMDS_MeshElement* newElem = 0;
7493                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7494                   myLastCreatedElems.Append(newElem);
7495                   if ( aShapeId && newElem )
7496                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7497                   rmElemIds.push_back(elem->GetID());
7498                 }
7499             }
7500             else {
7501               rmElemIds.push_back(elem->GetID());
7502             }
7503           }
7504         }
7505         else {
7506         }
7507
7508         continue;
7509       } // poly element
7510
7511       // Regular elements
7512       // TODO not all the possible cases are solved. Find something more generic?
7513       switch ( nbNodes ) {
7514       case 2: ///////////////////////////////////// EDGE
7515         isOk = false; break;
7516       case 3: ///////////////////////////////////// TRIANGLE
7517         isOk = false; break;
7518       case 4:
7519         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7520           isOk = false;
7521         else { //////////////////////////////////// QUADRANGLE
7522           if ( nbUniqueNodes < 3 )
7523             isOk = false;
7524           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7525             isOk = false; // opposite nodes stick
7526           //MESSAGE("isOk " << isOk);
7527         }
7528         break;
7529       case 6: ///////////////////////////////////// PENTAHEDRON
7530         if ( nbUniqueNodes == 4 ) {
7531           // ---------------------------------> tetrahedron
7532           if (nbRepl == 3 &&
7533               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7534             // all top nodes stick: reverse a bottom
7535             uniqueNodes[ 0 ] = curNodes [ 1 ];
7536             uniqueNodes[ 1 ] = curNodes [ 0 ];
7537           }
7538           else if (nbRepl == 3 &&
7539                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7540             // all bottom nodes stick: set a top before
7541             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7542             uniqueNodes[ 0 ] = curNodes [ 3 ];
7543             uniqueNodes[ 1 ] = curNodes [ 4 ];
7544             uniqueNodes[ 2 ] = curNodes [ 5 ];
7545           }
7546           else if (nbRepl == 4 &&
7547                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7548             // a lateral face turns into a line: reverse a bottom
7549             uniqueNodes[ 0 ] = curNodes [ 1 ];
7550             uniqueNodes[ 1 ] = curNodes [ 0 ];
7551           }
7552           else
7553             isOk = false;
7554         }
7555         else if ( nbUniqueNodes == 5 ) {
7556           // PENTAHEDRON --------------------> 2 tetrahedrons
7557           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7558             // a bottom node sticks with a linked top one
7559             // 1.
7560             SMDS_MeshElement* newElem =
7561               aMesh->AddVolume(curNodes[ 3 ],
7562                                curNodes[ 4 ],
7563                                curNodes[ 5 ],
7564                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7565             myLastCreatedElems.Append(newElem);
7566             if ( aShapeId )
7567               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7568             // 2. : reverse a bottom
7569             uniqueNodes[ 0 ] = curNodes [ 1 ];
7570             uniqueNodes[ 1 ] = curNodes [ 0 ];
7571             nbUniqueNodes = 4;
7572           }
7573           else
7574             isOk = false;
7575         }
7576         else
7577           isOk = false;
7578         break;
7579       case 8: {
7580         if(elem->IsQuadratic()) { // Quadratic quadrangle
7581           //   1    5    2
7582           //    +---+---+
7583           //    |       |
7584           //    |       |
7585           //   4+       +6
7586           //    |       |
7587           //    |       |
7588           //    +---+---+
7589           //   0    7    3
7590           isOk = false;
7591           if(nbRepl==2) {
7592             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7593           }
7594           if(nbRepl==3) {
7595             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7596             nbUniqueNodes = 6;
7597             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7598               uniqueNodes[0] = curNodes[0];
7599               uniqueNodes[1] = curNodes[2];
7600               uniqueNodes[2] = curNodes[3];
7601               uniqueNodes[3] = curNodes[5];
7602               uniqueNodes[4] = curNodes[6];
7603               uniqueNodes[5] = curNodes[7];
7604               isOk = true;
7605             }
7606             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7607               uniqueNodes[0] = curNodes[0];
7608               uniqueNodes[1] = curNodes[1];
7609               uniqueNodes[2] = curNodes[2];
7610               uniqueNodes[3] = curNodes[4];
7611               uniqueNodes[4] = curNodes[5];
7612               uniqueNodes[5] = curNodes[6];
7613               isOk = true;
7614             }
7615             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7616               uniqueNodes[0] = curNodes[1];
7617               uniqueNodes[1] = curNodes[2];
7618               uniqueNodes[2] = curNodes[3];
7619               uniqueNodes[3] = curNodes[5];
7620               uniqueNodes[4] = curNodes[6];
7621               uniqueNodes[5] = curNodes[0];
7622               isOk = true;
7623             }
7624             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7625               uniqueNodes[0] = curNodes[0];
7626               uniqueNodes[1] = curNodes[1];
7627               uniqueNodes[2] = curNodes[3];
7628               uniqueNodes[3] = curNodes[4];
7629               uniqueNodes[4] = curNodes[6];
7630               uniqueNodes[5] = curNodes[7];
7631               isOk = true;
7632             }
7633             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7634               uniqueNodes[0] = curNodes[0];
7635               uniqueNodes[1] = curNodes[2];
7636               uniqueNodes[2] = curNodes[3];
7637               uniqueNodes[3] = curNodes[1];
7638               uniqueNodes[4] = curNodes[6];
7639               uniqueNodes[5] = curNodes[7];
7640               isOk = true;
7641             }
7642             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7643               uniqueNodes[0] = curNodes[0];
7644               uniqueNodes[1] = curNodes[1];
7645               uniqueNodes[2] = curNodes[2];
7646               uniqueNodes[3] = curNodes[4];
7647               uniqueNodes[4] = curNodes[5];
7648               uniqueNodes[5] = curNodes[7];
7649               isOk = true;
7650             }
7651             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7652               uniqueNodes[0] = curNodes[0];
7653               uniqueNodes[1] = curNodes[1];
7654               uniqueNodes[2] = curNodes[3];
7655               uniqueNodes[3] = curNodes[4];
7656               uniqueNodes[4] = curNodes[2];
7657               uniqueNodes[5] = curNodes[7];
7658               isOk = true;
7659             }
7660             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7661               uniqueNodes[0] = curNodes[0];
7662               uniqueNodes[1] = curNodes[1];
7663               uniqueNodes[2] = curNodes[2];
7664               uniqueNodes[3] = curNodes[4];
7665               uniqueNodes[4] = curNodes[5];
7666               uniqueNodes[5] = curNodes[3];
7667               isOk = true;
7668             }
7669           }
7670           if(nbRepl==4) {
7671             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7672           }
7673           if(nbRepl==5) {
7674             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7675           }
7676           break;
7677         }
7678         //////////////////////////////////// HEXAHEDRON
7679         isOk = false;
7680         SMDS_VolumeTool hexa (elem);
7681         hexa.SetExternalNormal();
7682         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7683           //////////////////////// HEX ---> 1 tetrahedron
7684           for ( int iFace = 0; iFace < 6; iFace++ ) {
7685             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7686             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7687                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7688                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7689               // one face turns into a point ...
7690               int iOppFace = hexa.GetOppFaceIndex( iFace );
7691               ind = hexa.GetFaceNodesIndices( iOppFace );
7692               int nbStick = 0;
7693               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7694                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7695                   nbStick++;
7696               }
7697               if ( nbStick == 1 ) {
7698                 // ... and the opposite one - into a triangle.
7699                 // set a top node
7700                 ind = hexa.GetFaceNodesIndices( iFace );
7701                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7702                 isOk = true;
7703               }
7704               break;
7705             }
7706           }
7707         }
7708         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7709           //////////////////////// HEX ---> 1 prism
7710           int nbTria = 0, iTria[3];
7711           const int *ind; // indices of face nodes
7712           // look for triangular faces
7713           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7714             ind = hexa.GetFaceNodesIndices( iFace );
7715             TIDSortedNodeSet faceNodes;
7716             for ( iCur = 0; iCur < 4; iCur++ )
7717               faceNodes.insert( curNodes[ind[iCur]] );
7718             if ( faceNodes.size() == 3 )
7719               iTria[ nbTria++ ] = iFace;
7720           }
7721           // check if triangles are opposite
7722           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7723           {
7724             isOk = true;
7725             // set nodes of the bottom triangle
7726             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7727             vector<int> indB;
7728             for ( iCur = 0; iCur < 4; iCur++ )
7729               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7730                 indB.push_back( ind[iCur] );
7731             if ( !hexa.IsForward() )
7732               std::swap( indB[0], indB[2] );
7733             for ( iCur = 0; iCur < 3; iCur++ )
7734               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7735             // set nodes of the top triangle
7736             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7737             for ( iCur = 0; iCur < 3; ++iCur )
7738               for ( int j = 0; j < 4; ++j )
7739                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7740                 {
7741                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7742                   break;
7743                 }
7744           }
7745           break;
7746         }
7747         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7748           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7749           for ( int iFace = 0; iFace < 6; iFace++ ) {
7750             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7751             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7752                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7753                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7754               // one face turns into a point ...
7755               int iOppFace = hexa.GetOppFaceIndex( iFace );
7756               ind = hexa.GetFaceNodesIndices( iOppFace );
7757               int nbStick = 0;
7758               iUnique = 2;  // reverse a tetrahedron 1 bottom
7759               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7760                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7761                   nbStick++;
7762                 else if ( iUnique >= 0 )
7763                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7764               }
7765               if ( nbStick == 0 ) {
7766                 // ... and the opposite one is a quadrangle
7767                 // set a top node
7768                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7769                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7770                 nbUniqueNodes = 4;
7771                 // tetrahedron 2
7772                 SMDS_MeshElement* newElem =
7773                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7774                                    curNodes[ind[ 3 ]],
7775                                    curNodes[ind[ 2 ]],
7776                                    curNodes[indTop[ 0 ]]);
7777                 myLastCreatedElems.Append(newElem);
7778                 if ( aShapeId )
7779                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7780                 isOk = true;
7781               }
7782               break;
7783             }
7784           }
7785         }
7786         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7787           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7788           // find indices of quad and tri faces
7789           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7790           for ( iFace = 0; iFace < 6; iFace++ ) {
7791             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7792             nodeSet.clear();
7793             for ( iCur = 0; iCur < 4; iCur++ )
7794               nodeSet.insert( curNodes[ind[ iCur ]] );
7795             nbUniqueNodes = nodeSet.size();
7796             if ( nbUniqueNodes == 3 )
7797               iTriFace[ nbTri++ ] = iFace;
7798             else if ( nbUniqueNodes == 4 )
7799               iQuadFace[ nbQuad++ ] = iFace;
7800           }
7801           if (nbQuad == 2 && nbTri == 4 &&
7802               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7803             // 2 opposite quadrangles stuck with a diagonal;
7804             // sample groups of merged indices: (0-4)(2-6)
7805             // --------------------------------------------> 2 tetrahedrons
7806             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7807             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7808             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7809             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7810                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7811               // stuck with 0-2 diagonal
7812               i0  = ind1[ 3 ];
7813               i1d = ind1[ 0 ];
7814               i2  = ind1[ 1 ];
7815               i3d = ind1[ 2 ];
7816               i0t = ind2[ 1 ];
7817               i2t = ind2[ 3 ];
7818             }
7819             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7820                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7821               // stuck with 1-3 diagonal
7822               i0  = ind1[ 0 ];
7823               i1d = ind1[ 1 ];
7824               i2  = ind1[ 2 ];
7825               i3d = ind1[ 3 ];
7826               i0t = ind2[ 0 ];
7827               i2t = ind2[ 1 ];
7828             }
7829             else {
7830               ASSERT(0);
7831             }
7832             // tetrahedron 1
7833             uniqueNodes[ 0 ] = curNodes [ i0 ];
7834             uniqueNodes[ 1 ] = curNodes [ i1d ];
7835             uniqueNodes[ 2 ] = curNodes [ i3d ];
7836             uniqueNodes[ 3 ] = curNodes [ i0t ];
7837             nbUniqueNodes = 4;
7838             // tetrahedron 2
7839             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7840                                                          curNodes[ i2 ],
7841                                                          curNodes[ i3d ],
7842                                                          curNodes[ i2t ]);
7843             myLastCreatedElems.Append(newElem);
7844             if ( aShapeId )
7845               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7846             isOk = true;
7847           }
7848           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7849                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7850             // --------------------------------------------> prism
7851             // find 2 opposite triangles
7852             nbUniqueNodes = 6;
7853             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7854               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7855                 // find indices of kept and replaced nodes
7856                 // and fill unique nodes of 2 opposite triangles
7857                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7858                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7859                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7860                 // fill unique nodes
7861                 iUnique = 0;
7862                 isOk = true;
7863                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7864                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7865                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7866                   if ( n == nInit ) {
7867                     // iCur of a linked node of the opposite face (make normals co-directed):
7868                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7869                     // check that correspondent corners of triangles are linked
7870                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7871                       isOk = false;
7872                     else {
7873                       uniqueNodes[ iUnique ] = n;
7874                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7875                       iUnique++;
7876                     }
7877                   }
7878                 }
7879                 break;
7880               }
7881             }
7882           }
7883         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7884         else
7885         {
7886           MESSAGE("MergeNodes() removes hexahedron "<< elem);
7887         }
7888         break;
7889       } // HEXAHEDRON
7890
7891       default:
7892         isOk = false;
7893       } // switch ( nbNodes )
7894
7895     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7896
7897     if ( isOk ) { // the elem remains valid after sticking nodes
7898       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
7899       {
7900         // Change nodes of polyedre
7901         const SMDS_VtkVolume* aPolyedre =
7902           dynamic_cast<const SMDS_VtkVolume*>( elem );
7903         if (aPolyedre) {
7904           int nbFaces = aPolyedre->NbFaces();
7905
7906           vector<const SMDS_MeshNode *> poly_nodes;
7907           vector<int> quantities (nbFaces);
7908
7909           for (int iface = 1; iface <= nbFaces; iface++) {
7910             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7911             quantities[iface - 1] = nbFaceNodes;
7912
7913             for (inode = 1; inode <= nbFaceNodes; inode++) {
7914               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7915
7916               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7917               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7918                 curNode = (*nnIt).second;
7919               }
7920               poly_nodes.push_back(curNode);
7921             }
7922           }
7923           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7924         }
7925       }
7926       else // replace non-polyhedron elements
7927       {
7928         const SMDSAbs_ElementType etyp = elem->GetType();
7929         const int elemId               = elem->GetID();
7930         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
7931         uniqueNodes.resize(nbUniqueNodes);
7932
7933         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
7934
7935         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7936         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
7937         if ( sm && newElem )
7938           sm->AddElement( newElem );
7939         if ( elem != newElem )
7940           ReplaceElemInGroups( elem, newElem, aMesh );
7941       }
7942     }
7943     else {
7944       // Remove invalid regular element or invalid polygon
7945       rmElemIds.push_back( elem->GetID() );
7946     }
7947
7948   } // loop on elements
7949
7950   // Remove bad elements, then equal nodes (order important)
7951
7952   Remove( rmElemIds, false );
7953   Remove( rmNodeIds, true );
7954
7955 }
7956
7957
7958 // ========================================================
7959 // class   : SortableElement
7960 // purpose : allow sorting elements basing on their nodes
7961 // ========================================================
7962 class SortableElement : public set <const SMDS_MeshElement*>
7963 {
7964 public:
7965
7966   SortableElement( const SMDS_MeshElement* theElem )
7967   {
7968     myElem = theElem;
7969     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7970     while ( nodeIt->more() )
7971       this->insert( nodeIt->next() );
7972   }
7973
7974   const SMDS_MeshElement* Get() const
7975   { return myElem; }
7976
7977   void Set(const SMDS_MeshElement* e) const
7978   { myElem = e; }
7979
7980
7981 private:
7982   mutable const SMDS_MeshElement* myElem;
7983 };
7984
7985 //=======================================================================
7986 //function : FindEqualElements
7987 //purpose  : Return list of group of elements built on the same nodes.
7988 //           Search among theElements or in the whole mesh if theElements is empty
7989 //=======================================================================
7990 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7991                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7992 {
7993   myLastCreatedElems.Clear();
7994   myLastCreatedNodes.Clear();
7995
7996   typedef set<const SMDS_MeshElement*> TElemsSet;
7997   typedef map< SortableElement, int > TMapOfNodeSet;
7998   typedef list<int> TGroupOfElems;
7999
8000   TElemsSet elems;
8001   if ( theElements.empty() )
8002   { // get all elements in the mesh
8003     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
8004     while ( eIt->more() )
8005       elems.insert( elems.end(), eIt->next());
8006   }
8007   else
8008     elems = theElements;
8009
8010   vector< TGroupOfElems > arrayOfGroups;
8011   TGroupOfElems groupOfElems;
8012   TMapOfNodeSet mapOfNodeSet;
8013
8014   TElemsSet::iterator elemIt = elems.begin();
8015   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
8016     const SMDS_MeshElement* curElem = *elemIt;
8017     SortableElement SE(curElem);
8018     int ind = -1;
8019     // check uniqueness
8020     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
8021     if( !(pp.second) ) {
8022       TMapOfNodeSet::iterator& itSE = pp.first;
8023       ind = (*itSE).second;
8024       arrayOfGroups[ind].push_back(curElem->GetID());
8025     }
8026     else {
8027       groupOfElems.clear();
8028       groupOfElems.push_back(curElem->GetID());
8029       arrayOfGroups.push_back(groupOfElems);
8030       i++;
8031     }
8032   }
8033
8034   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
8035   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8036     groupOfElems = *groupIt;
8037     if ( groupOfElems.size() > 1 ) {
8038       groupOfElems.sort();
8039       theGroupsOfElementsID.push_back(groupOfElems);
8040     }
8041   }
8042 }
8043
8044 //=======================================================================
8045 //function : MergeElements
8046 //purpose  : In each given group, substitute all elements by the first one.
8047 //=======================================================================
8048
8049 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8050 {
8051   myLastCreatedElems.Clear();
8052   myLastCreatedNodes.Clear();
8053
8054   typedef list<int> TListOfIDs;
8055   TListOfIDs rmElemIds; // IDs of elems to remove
8056
8057   SMESHDS_Mesh* aMesh = GetMeshDS();
8058
8059   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8060   while ( groupsIt != theGroupsOfElementsID.end() ) {
8061     TListOfIDs& aGroupOfElemID = *groupsIt;
8062     aGroupOfElemID.sort();
8063     int elemIDToKeep = aGroupOfElemID.front();
8064     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8065     aGroupOfElemID.pop_front();
8066     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8067     while ( idIt != aGroupOfElemID.end() ) {
8068       int elemIDToRemove = *idIt;
8069       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8070       // add the kept element in groups of removed one (PAL15188)
8071       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8072       rmElemIds.push_back( elemIDToRemove );
8073       ++idIt;
8074     }
8075     ++groupsIt;
8076   }
8077
8078   Remove( rmElemIds, false );
8079 }
8080
8081 //=======================================================================
8082 //function : MergeEqualElements
8083 //purpose  : Remove all but one of elements built on the same nodes.
8084 //=======================================================================
8085
8086 void SMESH_MeshEditor::MergeEqualElements()
8087 {
8088   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8089                                                  to merge equal elements in the whole mesh */
8090   TListOfListOfElementsID aGroupsOfElementsID;
8091   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8092   MergeElements(aGroupsOfElementsID);
8093 }
8094
8095 //=======================================================================
8096 //function : FindFaceInSet
8097 //purpose  : Return a face having linked nodes n1 and n2 and which is
8098 //           - not in avoidSet,
8099 //           - in elemSet provided that !elemSet.empty()
8100 //           i1 and i2 optionally returns indices of n1 and n2
8101 //=======================================================================
8102
8103 const SMDS_MeshElement*
8104 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8105                                 const SMDS_MeshNode*    n2,
8106                                 const TIDSortedElemSet& elemSet,
8107                                 const TIDSortedElemSet& avoidSet,
8108                                 int*                    n1ind,
8109                                 int*                    n2ind)
8110
8111 {
8112   int i1, i2;
8113   const SMDS_MeshElement* face = 0;
8114
8115   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8116   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8117   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8118   {
8119     //MESSAGE("in while ( invElemIt->more() && !face )");
8120     const SMDS_MeshElement* elem = invElemIt->next();
8121     if (avoidSet.count( elem ))
8122       continue;
8123     if ( !elemSet.empty() && !elemSet.count( elem ))
8124       continue;
8125     // index of n1
8126     i1 = elem->GetNodeIndex( n1 );
8127     // find a n2 linked to n1
8128     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8129     for ( int di = -1; di < 2 && !face; di += 2 )
8130     {
8131       i2 = (i1+di+nbN) % nbN;
8132       if ( elem->GetNode( i2 ) == n2 )
8133         face = elem;
8134     }
8135     if ( !face && elem->IsQuadratic())
8136     {
8137       // analysis for quadratic elements using all nodes
8138       const SMDS_VtkFace* F =
8139         dynamic_cast<const SMDS_VtkFace*>(elem);
8140       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8141       // use special nodes iterator
8142       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8143       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8144       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8145       {
8146         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8147         if ( n1 == prevN && n2 == n )
8148         {
8149           face = elem;
8150         }
8151         else if ( n2 == prevN && n1 == n )
8152         {
8153           face = elem; swap( i1, i2 );
8154         }
8155         prevN = n;
8156       }
8157     }
8158   }
8159   if ( n1ind ) *n1ind = i1;
8160   if ( n2ind ) *n2ind = i2;
8161   return face;
8162 }
8163
8164 //=======================================================================
8165 //function : findAdjacentFace
8166 //purpose  :
8167 //=======================================================================
8168
8169 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8170                                                 const SMDS_MeshNode* n2,
8171                                                 const SMDS_MeshElement* elem)
8172 {
8173   TIDSortedElemSet elemSet, avoidSet;
8174   if ( elem )
8175     avoidSet.insert ( elem );
8176   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8177 }
8178
8179 //=======================================================================
8180 //function : FindFreeBorder
8181 //purpose  :
8182 //=======================================================================
8183
8184 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8185
8186 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8187                                        const SMDS_MeshNode*             theSecondNode,
8188                                        const SMDS_MeshNode*             theLastNode,
8189                                        list< const SMDS_MeshNode* > &   theNodes,
8190                                        list< const SMDS_MeshElement* >& theFaces)
8191 {
8192   if ( !theFirstNode || !theSecondNode )
8193     return false;
8194   // find border face between theFirstNode and theSecondNode
8195   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8196   if ( !curElem )
8197     return false;
8198
8199   theFaces.push_back( curElem );
8200   theNodes.push_back( theFirstNode );
8201   theNodes.push_back( theSecondNode );
8202
8203   //vector<const SMDS_MeshNode*> nodes;
8204   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8205   TIDSortedElemSet foundElems;
8206   bool needTheLast = ( theLastNode != 0 );
8207
8208   while ( nStart != theLastNode ) {
8209     if ( nStart == theFirstNode )
8210       return !needTheLast;
8211
8212     // find all free border faces sharing form nStart
8213
8214     list< const SMDS_MeshElement* > curElemList;
8215     list< const SMDS_MeshNode* > nStartList;
8216     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8217     while ( invElemIt->more() ) {
8218       const SMDS_MeshElement* e = invElemIt->next();
8219       if ( e == curElem || foundElems.insert( e ).second ) {
8220         // get nodes
8221         int iNode = 0, nbNodes = e->NbNodes();
8222         //const SMDS_MeshNode* nodes[nbNodes+1];
8223         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8224
8225         if(e->IsQuadratic()) {
8226           const SMDS_VtkFace* F =
8227             dynamic_cast<const SMDS_VtkFace*>(e);
8228           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8229           // use special nodes iterator
8230           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8231           while( anIter->more() ) {
8232             nodes[ iNode++ ] = cast2Node(anIter->next());
8233           }
8234         }
8235         else {
8236           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8237           while ( nIt->more() )
8238             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8239         }
8240         nodes[ iNode ] = nodes[ 0 ];
8241         // check 2 links
8242         for ( iNode = 0; iNode < nbNodes; iNode++ )
8243           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8244                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8245               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8246           {
8247             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8248             curElemList.push_back( e );
8249           }
8250       }
8251     }
8252     // analyse the found
8253
8254     int nbNewBorders = curElemList.size();
8255     if ( nbNewBorders == 0 ) {
8256       // no free border furthermore
8257       return !needTheLast;
8258     }
8259     else if ( nbNewBorders == 1 ) {
8260       // one more element found
8261       nIgnore = nStart;
8262       nStart = nStartList.front();
8263       curElem = curElemList.front();
8264       theFaces.push_back( curElem );
8265       theNodes.push_back( nStart );
8266     }
8267     else {
8268       // several continuations found
8269       list< const SMDS_MeshElement* >::iterator curElemIt;
8270       list< const SMDS_MeshNode* >::iterator nStartIt;
8271       // check if one of them reached the last node
8272       if ( needTheLast ) {
8273         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8274              curElemIt!= curElemList.end();
8275              curElemIt++, nStartIt++ )
8276           if ( *nStartIt == theLastNode ) {
8277             theFaces.push_back( *curElemIt );
8278             theNodes.push_back( *nStartIt );
8279             return true;
8280           }
8281       }
8282       // find the best free border by the continuations
8283       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8284       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8285       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8286            curElemIt!= curElemList.end();
8287            curElemIt++, nStartIt++ )
8288       {
8289         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8290         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8291         // find one more free border
8292         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8293           cNL->clear();
8294           cFL->clear();
8295         }
8296         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8297           // choice: clear a worse one
8298           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8299           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8300           contNodes[ iWorse ].clear();
8301           contFaces[ iWorse ].clear();
8302         }
8303       }
8304       if ( contNodes[0].empty() && contNodes[1].empty() )
8305         return false;
8306
8307       // append the best free border
8308       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8309       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8310       theNodes.pop_back(); // remove nIgnore
8311       theNodes.pop_back(); // remove nStart
8312       theFaces.pop_back(); // remove curElem
8313       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8314       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8315       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8316       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8317       return true;
8318
8319     } // several continuations found
8320   } // while ( nStart != theLastNode )
8321
8322   return true;
8323 }
8324
8325 //=======================================================================
8326 //function : CheckFreeBorderNodes
8327 //purpose  : Return true if the tree nodes are on a free border
8328 //=======================================================================
8329
8330 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8331                                             const SMDS_MeshNode* theNode2,
8332                                             const SMDS_MeshNode* theNode3)
8333 {
8334   list< const SMDS_MeshNode* > nodes;
8335   list< const SMDS_MeshElement* > faces;
8336   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8337 }
8338
8339 //=======================================================================
8340 //function : SewFreeBorder
8341 //purpose  :
8342 //=======================================================================
8343
8344 SMESH_MeshEditor::Sew_Error
8345 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8346                                  const SMDS_MeshNode* theBordSecondNode,
8347                                  const SMDS_MeshNode* theBordLastNode,
8348                                  const SMDS_MeshNode* theSideFirstNode,
8349                                  const SMDS_MeshNode* theSideSecondNode,
8350                                  const SMDS_MeshNode* theSideThirdNode,
8351                                  const bool           theSideIsFreeBorder,
8352                                  const bool           toCreatePolygons,
8353                                  const bool           toCreatePolyedrs)
8354 {
8355   myLastCreatedElems.Clear();
8356   myLastCreatedNodes.Clear();
8357
8358   MESSAGE("::SewFreeBorder()");
8359   Sew_Error aResult = SEW_OK;
8360
8361   // ====================================
8362   //    find side nodes and elements
8363   // ====================================
8364
8365   list< const SMDS_MeshNode* > nSide[ 2 ];
8366   list< const SMDS_MeshElement* > eSide[ 2 ];
8367   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8368   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8369
8370   // Free border 1
8371   // --------------
8372   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8373                       nSide[0], eSide[0])) {
8374     MESSAGE(" Free Border 1 not found " );
8375     aResult = SEW_BORDER1_NOT_FOUND;
8376   }
8377   if (theSideIsFreeBorder) {
8378     // Free border 2
8379     // --------------
8380     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8381                         nSide[1], eSide[1])) {
8382       MESSAGE(" Free Border 2 not found " );
8383       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8384     }
8385   }
8386   if ( aResult != SEW_OK )
8387     return aResult;
8388
8389   if (!theSideIsFreeBorder) {
8390     // Side 2
8391     // --------------
8392
8393     // -------------------------------------------------------------------------
8394     // Algo:
8395     // 1. If nodes to merge are not coincident, move nodes of the free border
8396     //    from the coord sys defined by the direction from the first to last
8397     //    nodes of the border to the correspondent sys of the side 2
8398     // 2. On the side 2, find the links most co-directed with the correspondent
8399     //    links of the free border
8400     // -------------------------------------------------------------------------
8401
8402     // 1. Since sewing may break if there are volumes to split on the side 2,
8403     //    we wont move nodes but just compute new coordinates for them
8404     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8405     TNodeXYZMap nBordXYZ;
8406     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8407     list< const SMDS_MeshNode* >::iterator nBordIt;
8408
8409     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8410     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8411     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8412     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8413     double tol2 = 1.e-8;
8414     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8415     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8416       // Need node movement.
8417
8418       // find X and Z axes to create trsf
8419       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8420       gp_Vec X = Zs ^ Zb;
8421       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8422         // Zb || Zs
8423         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8424
8425       // coord systems
8426       gp_Ax3 toBordAx( Pb1, Zb, X );
8427       gp_Ax3 fromSideAx( Ps1, Zs, X );
8428       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8429       // set trsf
8430       gp_Trsf toBordSys, fromSide2Sys;
8431       toBordSys.SetTransformation( toBordAx );
8432       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8433       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8434
8435       // move
8436       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8437         const SMDS_MeshNode* n = *nBordIt;
8438         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8439         toBordSys.Transforms( xyz );
8440         fromSide2Sys.Transforms( xyz );
8441         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8442       }
8443     }
8444     else {
8445       // just insert nodes XYZ in the nBordXYZ map
8446       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8447         const SMDS_MeshNode* n = *nBordIt;
8448         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8449       }
8450     }
8451
8452     // 2. On the side 2, find the links most co-directed with the correspondent
8453     //    links of the free border
8454
8455     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8456     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8457     sideNodes.push_back( theSideFirstNode );
8458
8459     bool hasVolumes = false;
8460     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8461     set<long> foundSideLinkIDs, checkedLinkIDs;
8462     SMDS_VolumeTool volume;
8463     //const SMDS_MeshNode* faceNodes[ 4 ];
8464
8465     const SMDS_MeshNode*    sideNode;
8466     const SMDS_MeshElement* sideElem;
8467     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8468     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8469     nBordIt = bordNodes.begin();
8470     nBordIt++;
8471     // border node position and border link direction to compare with
8472     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8473     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8474     // choose next side node by link direction or by closeness to
8475     // the current border node:
8476     bool searchByDir = ( *nBordIt != theBordLastNode );
8477     do {
8478       // find the next node on the Side 2
8479       sideNode = 0;
8480       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8481       long linkID;
8482       checkedLinkIDs.clear();
8483       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8484
8485       // loop on inverse elements of current node (prevSideNode) on the Side 2
8486       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8487       while ( invElemIt->more() )
8488       {
8489         const SMDS_MeshElement* elem = invElemIt->next();
8490         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8491         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8492         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8493         bool isVolume = volume.Set( elem );
8494         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8495         if ( isVolume ) // --volume
8496           hasVolumes = true;
8497         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8498           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8499           if(elem->IsQuadratic()) {
8500             const SMDS_VtkFace* F =
8501               dynamic_cast<const SMDS_VtkFace*>(elem);
8502             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8503             // use special nodes iterator
8504             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8505             while( anIter->more() ) {
8506               nodes[ iNode ] = cast2Node(anIter->next());
8507               if ( nodes[ iNode++ ] == prevSideNode )
8508                 iPrevNode = iNode - 1;
8509             }
8510           }
8511           else {
8512             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8513             while ( nIt->more() ) {
8514               nodes[ iNode ] = cast2Node( nIt->next() );
8515               if ( nodes[ iNode++ ] == prevSideNode )
8516                 iPrevNode = iNode - 1;
8517             }
8518           }
8519           // there are 2 links to check
8520           nbNodes = 2;
8521         }
8522         else // --edge
8523           continue;
8524         // loop on links, to be precise, on the second node of links
8525         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8526           const SMDS_MeshNode* n = nodes[ iNode ];
8527           if ( isVolume ) {
8528             if ( !volume.IsLinked( n, prevSideNode ))
8529               continue;
8530           }
8531           else {
8532             if ( iNode ) // a node before prevSideNode
8533               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8534             else         // a node after prevSideNode
8535               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8536           }
8537           // check if this link was already used
8538           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8539           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8540           if (!isJustChecked &&
8541               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8542           {
8543             // test a link geometrically
8544             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8545             bool linkIsBetter = false;
8546             double dot = 0.0, dist = 0.0;
8547             if ( searchByDir ) { // choose most co-directed link
8548               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8549               linkIsBetter = ( dot > maxDot );
8550             }
8551             else { // choose link with the node closest to bordPos
8552               dist = ( nextXYZ - bordPos ).SquareModulus();
8553               linkIsBetter = ( dist < minDist );
8554             }
8555             if ( linkIsBetter ) {
8556               maxDot = dot;
8557               minDist = dist;
8558               linkID = iLink;
8559               sideNode = n;
8560               sideElem = elem;
8561             }
8562           }
8563         }
8564       } // loop on inverse elements of prevSideNode
8565
8566       if ( !sideNode ) {
8567         MESSAGE(" Cant find path by links of the Side 2 ");
8568         return SEW_BAD_SIDE_NODES;
8569       }
8570       sideNodes.push_back( sideNode );
8571       sideElems.push_back( sideElem );
8572       foundSideLinkIDs.insert ( linkID );
8573       prevSideNode = sideNode;
8574
8575       if ( *nBordIt == theBordLastNode )
8576         searchByDir = false;
8577       else {
8578         // find the next border link to compare with
8579         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8580         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8581         // move to next border node if sideNode is before forward border node (bordPos)
8582         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8583           prevBordNode = *nBordIt;
8584           nBordIt++;
8585           bordPos = nBordXYZ[ *nBordIt ];
8586           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8587           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8588         }
8589       }
8590     }
8591     while ( sideNode != theSideSecondNode );
8592
8593     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8594       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8595       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8596     }
8597   } // end nodes search on the side 2
8598
8599   // ============================
8600   // sew the border to the side 2
8601   // ============================
8602
8603   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8604   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8605
8606   TListOfListOfNodes nodeGroupsToMerge;
8607   if ( nbNodes[0] == nbNodes[1] ||
8608        ( theSideIsFreeBorder && !theSideThirdNode)) {
8609
8610     // all nodes are to be merged
8611
8612     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8613          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8614          nIt[0]++, nIt[1]++ )
8615     {
8616       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8617       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8618       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8619     }
8620   }
8621   else {
8622
8623     // insert new nodes into the border and the side to get equal nb of segments
8624
8625     // get normalized parameters of nodes on the borders
8626     //double param[ 2 ][ maxNbNodes ];
8627     double* param[ 2 ];
8628     param[0] = new double [ maxNbNodes ];
8629     param[1] = new double [ maxNbNodes ];
8630     int iNode, iBord;
8631     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8632       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8633       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8634       const SMDS_MeshNode* nPrev = *nIt;
8635       double bordLength = 0;
8636       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8637         const SMDS_MeshNode* nCur = *nIt;
8638         gp_XYZ segment (nCur->X() - nPrev->X(),
8639                         nCur->Y() - nPrev->Y(),
8640                         nCur->Z() - nPrev->Z());
8641         double segmentLen = segment.Modulus();
8642         bordLength += segmentLen;
8643         param[ iBord ][ iNode ] = bordLength;
8644         nPrev = nCur;
8645       }
8646       // normalize within [0,1]
8647       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8648         param[ iBord ][ iNode ] /= bordLength;
8649       }
8650     }
8651
8652     // loop on border segments
8653     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8654     int i[ 2 ] = { 0, 0 };
8655     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8656     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8657
8658     TElemOfNodeListMap insertMap;
8659     TElemOfNodeListMap::iterator insertMapIt;
8660     // insertMap is
8661     // key:   elem to insert nodes into
8662     // value: 2 nodes to insert between + nodes to be inserted
8663     do {
8664       bool next[ 2 ] = { false, false };
8665
8666       // find min adjacent segment length after sewing
8667       double nextParam = 10., prevParam = 0;
8668       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8669         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8670           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8671         if ( i[ iBord ] > 0 )
8672           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8673       }
8674       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8675       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8676       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8677
8678       // choose to insert or to merge nodes
8679       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8680       if ( Abs( du ) <= minSegLen * 0.2 ) {
8681         // merge
8682         // ------
8683         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8684         const SMDS_MeshNode* n0 = *nIt[0];
8685         const SMDS_MeshNode* n1 = *nIt[1];
8686         nodeGroupsToMerge.back().push_back( n1 );
8687         nodeGroupsToMerge.back().push_back( n0 );
8688         // position of node of the border changes due to merge
8689         param[ 0 ][ i[0] ] += du;
8690         // move n1 for the sake of elem shape evaluation during insertion.
8691         // n1 will be removed by MergeNodes() anyway
8692         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8693         next[0] = next[1] = true;
8694       }
8695       else {
8696         // insert
8697         // ------
8698         int intoBord = ( du < 0 ) ? 0 : 1;
8699         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8700         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8701         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8702         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8703         if ( intoBord == 1 ) {
8704           // move node of the border to be on a link of elem of the side
8705           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8706           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8707           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8708           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8709           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8710         }
8711         insertMapIt = insertMap.find( elem );
8712         bool notFound = ( insertMapIt == insertMap.end() );
8713         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8714         if ( otherLink ) {
8715           // insert into another link of the same element:
8716           // 1. perform insertion into the other link of the elem
8717           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8718           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8719           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8720           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8721           // 2. perform insertion into the link of adjacent faces
8722           while (true) {
8723             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8724             if ( adjElem )
8725               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8726             else
8727               break;
8728           }
8729           if (toCreatePolyedrs) {
8730             // perform insertion into the links of adjacent volumes
8731             UpdateVolumes(n12, n22, nodeList);
8732           }
8733           // 3. find an element appeared on n1 and n2 after the insertion
8734           insertMap.erase( elem );
8735           elem = findAdjacentFace( n1, n2, 0 );
8736         }
8737         if ( notFound || otherLink ) {
8738           // add element and nodes of the side into the insertMap
8739           insertMapIt = insertMap.insert
8740             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8741           (*insertMapIt).second.push_back( n1 );
8742           (*insertMapIt).second.push_back( n2 );
8743         }
8744         // add node to be inserted into elem
8745         (*insertMapIt).second.push_back( nIns );
8746         next[ 1 - intoBord ] = true;
8747       }
8748
8749       // go to the next segment
8750       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8751         if ( next[ iBord ] ) {
8752           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8753             eIt[ iBord ]++;
8754           nPrev[ iBord ] = *nIt[ iBord ];
8755           nIt[ iBord ]++; i[ iBord ]++;
8756         }
8757       }
8758     }
8759     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8760
8761     // perform insertion of nodes into elements
8762
8763     for (insertMapIt = insertMap.begin();
8764          insertMapIt != insertMap.end();
8765          insertMapIt++ )
8766     {
8767       const SMDS_MeshElement* elem = (*insertMapIt).first;
8768       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8769       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8770       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8771
8772       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8773
8774       if ( !theSideIsFreeBorder ) {
8775         // look for and insert nodes into the faces adjacent to elem
8776         while (true) {
8777           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8778           if ( adjElem )
8779             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8780           else
8781             break;
8782         }
8783       }
8784       if (toCreatePolyedrs) {
8785         // perform insertion into the links of adjacent volumes
8786         UpdateVolumes(n1, n2, nodeList);
8787       }
8788     }
8789
8790     delete param[0];
8791     delete param[1];
8792   } // end: insert new nodes
8793
8794   MergeNodes ( nodeGroupsToMerge );
8795
8796   return aResult;
8797 }
8798
8799 //=======================================================================
8800 //function : InsertNodesIntoLink
8801 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8802 //           and theBetweenNode2 and split theElement
8803 //=======================================================================
8804
8805 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8806                                            const SMDS_MeshNode*        theBetweenNode1,
8807                                            const SMDS_MeshNode*        theBetweenNode2,
8808                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8809                                            const bool                  toCreatePoly)
8810 {
8811   if ( theFace->GetType() != SMDSAbs_Face ) return;
8812
8813   // find indices of 2 link nodes and of the rest nodes
8814   int iNode = 0, il1, il2, i3, i4;
8815   il1 = il2 = i3 = i4 = -1;
8816   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8817   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8818
8819   if(theFace->IsQuadratic()) {
8820     const SMDS_VtkFace* F =
8821       dynamic_cast<const SMDS_VtkFace*>(theFace);
8822     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8823     // use special nodes iterator
8824     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8825     while( anIter->more() ) {
8826       const SMDS_MeshNode* n = cast2Node(anIter->next());
8827       if ( n == theBetweenNode1 )
8828         il1 = iNode;
8829       else if ( n == theBetweenNode2 )
8830         il2 = iNode;
8831       else if ( i3 < 0 )
8832         i3 = iNode;
8833       else
8834         i4 = iNode;
8835       nodes[ iNode++ ] = n;
8836     }
8837   }
8838   else {
8839     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8840     while ( nodeIt->more() ) {
8841       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8842       if ( n == theBetweenNode1 )
8843         il1 = iNode;
8844       else if ( n == theBetweenNode2 )
8845         il2 = iNode;
8846       else if ( i3 < 0 )
8847         i3 = iNode;
8848       else
8849         i4 = iNode;
8850       nodes[ iNode++ ] = n;
8851     }
8852   }
8853   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8854     return ;
8855
8856   // arrange link nodes to go one after another regarding the face orientation
8857   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8858   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8859   if ( reverse ) {
8860     iNode = il1;
8861     il1 = il2;
8862     il2 = iNode;
8863     aNodesToInsert.reverse();
8864   }
8865   // check that not link nodes of a quadrangles are in good order
8866   int nbFaceNodes = theFace->NbNodes();
8867   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8868     iNode = i3;
8869     i3 = i4;
8870     i4 = iNode;
8871   }
8872
8873   if (toCreatePoly || theFace->IsPoly()) {
8874
8875     iNode = 0;
8876     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8877
8878     // add nodes of face up to first node of link
8879     bool isFLN = false;
8880
8881     if(theFace->IsQuadratic()) {
8882       const SMDS_VtkFace* F =
8883         dynamic_cast<const SMDS_VtkFace*>(theFace);
8884       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8885       // use special nodes iterator
8886       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8887       while( anIter->more()  && !isFLN ) {
8888         const SMDS_MeshNode* n = cast2Node(anIter->next());
8889         poly_nodes[iNode++] = n;
8890         if (n == nodes[il1]) {
8891           isFLN = true;
8892         }
8893       }
8894       // add nodes to insert
8895       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8896       for (; nIt != aNodesToInsert.end(); nIt++) {
8897         poly_nodes[iNode++] = *nIt;
8898       }
8899       // add nodes of face starting from last node of link
8900       while ( anIter->more() ) {
8901         poly_nodes[iNode++] = cast2Node(anIter->next());
8902       }
8903     }
8904     else {
8905       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8906       while ( nodeIt->more() && !isFLN ) {
8907         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8908         poly_nodes[iNode++] = n;
8909         if (n == nodes[il1]) {
8910           isFLN = true;
8911         }
8912       }
8913       // add nodes to insert
8914       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8915       for (; nIt != aNodesToInsert.end(); nIt++) {
8916         poly_nodes[iNode++] = *nIt;
8917       }
8918       // add nodes of face starting from last node of link
8919       while ( nodeIt->more() ) {
8920         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8921         poly_nodes[iNode++] = n;
8922       }
8923     }
8924
8925     // edit or replace the face
8926     SMESHDS_Mesh *aMesh = GetMeshDS();
8927
8928     if (theFace->IsPoly()) {
8929       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8930     }
8931     else {
8932       int aShapeId = FindShape( theFace );
8933
8934       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8935       myLastCreatedElems.Append(newElem);
8936       if ( aShapeId && newElem )
8937         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8938
8939       aMesh->RemoveElement(theFace);
8940     }
8941     return;
8942   }
8943
8944   SMESHDS_Mesh *aMesh = GetMeshDS();
8945   if( !theFace->IsQuadratic() ) {
8946
8947     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8948     int nbLinkNodes = 2 + aNodesToInsert.size();
8949     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8950     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8951     linkNodes[ 0 ] = nodes[ il1 ];
8952     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8953     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8954     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8955       linkNodes[ iNode++ ] = *nIt;
8956     }
8957     // decide how to split a quadrangle: compare possible variants
8958     // and choose which of splits to be a quadrangle
8959     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8960     if ( nbFaceNodes == 3 ) {
8961       iBestQuad = nbSplits;
8962       i4 = i3;
8963     }
8964     else if ( nbFaceNodes == 4 ) {
8965       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8966       double aBestRate = DBL_MAX;
8967       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8968         i1 = 0; i2 = 1;
8969         double aBadRate = 0;
8970         // evaluate elements quality
8971         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8972           if ( iSplit == iQuad ) {
8973             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8974                                    linkNodes[ i2++ ],
8975                                    nodes[ i3 ],
8976                                    nodes[ i4 ]);
8977             aBadRate += getBadRate( &quad, aCrit );
8978           }
8979           else {
8980             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8981                                    linkNodes[ i2++ ],
8982                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8983             aBadRate += getBadRate( &tria, aCrit );
8984           }
8985         }
8986         // choice
8987         if ( aBadRate < aBestRate ) {
8988           iBestQuad = iQuad;
8989           aBestRate = aBadRate;
8990         }
8991       }
8992     }
8993
8994     // create new elements
8995     int aShapeId = FindShape( theFace );
8996
8997     i1 = 0; i2 = 1;
8998     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8999       SMDS_MeshElement* newElem = 0;
9000       if ( iSplit == iBestQuad )
9001         newElem = aMesh->AddFace (linkNodes[ i1++ ],
9002                                   linkNodes[ i2++ ],
9003                                   nodes[ i3 ],
9004                                   nodes[ i4 ]);
9005       else
9006         newElem = aMesh->AddFace (linkNodes[ i1++ ],
9007                                   linkNodes[ i2++ ],
9008                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
9009       myLastCreatedElems.Append(newElem);
9010       if ( aShapeId && newElem )
9011         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9012     }
9013
9014     // change nodes of theFace
9015     const SMDS_MeshNode* newNodes[ 4 ];
9016     newNodes[ 0 ] = linkNodes[ i1 ];
9017     newNodes[ 1 ] = linkNodes[ i2 ];
9018     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
9019     newNodes[ 3 ] = nodes[ i4 ];
9020     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
9021     const SMDS_MeshElement* newElem = 0;
9022     if (iSplit == iBestQuad)
9023       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
9024     else
9025       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
9026     myLastCreatedElems.Append(newElem);
9027     if ( aShapeId && newElem )
9028       aMesh->SetMeshElementOnShape( newElem, aShapeId );
9029 } // end if(!theFace->IsQuadratic())
9030   else { // theFace is quadratic
9031     // we have to split theFace on simple triangles and one simple quadrangle
9032     int tmp = il1/2;
9033     int nbshift = tmp*2;
9034     // shift nodes in nodes[] by nbshift
9035     int i,j;
9036     for(i=0; i<nbshift; i++) {
9037       const SMDS_MeshNode* n = nodes[0];
9038       for(j=0; j<nbFaceNodes-1; j++) {
9039         nodes[j] = nodes[j+1];
9040       }
9041       nodes[nbFaceNodes-1] = n;
9042     }
9043     il1 = il1 - nbshift;
9044     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9045     //   n0      n1     n2    n0      n1     n2
9046     //     +-----+-----+        +-----+-----+
9047     //      \         /         |           |
9048     //       \       /          |           |
9049     //      n5+     +n3       n7+           +n3
9050     //         \   /            |           |
9051     //          \ /             |           |
9052     //           +              +-----+-----+
9053     //           n4           n6      n5     n4
9054
9055     // create new elements
9056     int aShapeId = FindShape( theFace );
9057
9058     int n1,n2,n3;
9059     if(nbFaceNodes==6) { // quadratic triangle
9060       SMDS_MeshElement* newElem =
9061         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9062       myLastCreatedElems.Append(newElem);
9063       if ( aShapeId && newElem )
9064         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9065       if(theFace->IsMediumNode(nodes[il1])) {
9066         // create quadrangle
9067         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9068         myLastCreatedElems.Append(newElem);
9069         if ( aShapeId && newElem )
9070           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9071         n1 = 1;
9072         n2 = 2;
9073         n3 = 3;
9074       }
9075       else {
9076         // create quadrangle
9077         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9078         myLastCreatedElems.Append(newElem);
9079         if ( aShapeId && newElem )
9080           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9081         n1 = 0;
9082         n2 = 1;
9083         n3 = 5;
9084       }
9085     }
9086     else { // nbFaceNodes==8 - quadratic quadrangle
9087       SMDS_MeshElement* newElem =
9088         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9089       myLastCreatedElems.Append(newElem);
9090       if ( aShapeId && newElem )
9091         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9092       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9093       myLastCreatedElems.Append(newElem);
9094       if ( aShapeId && newElem )
9095         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9096       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9097       myLastCreatedElems.Append(newElem);
9098       if ( aShapeId && newElem )
9099         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9100       if(theFace->IsMediumNode(nodes[il1])) {
9101         // create quadrangle
9102         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9103         myLastCreatedElems.Append(newElem);
9104         if ( aShapeId && newElem )
9105           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9106         n1 = 1;
9107         n2 = 2;
9108         n3 = 3;
9109       }
9110       else {
9111         // create quadrangle
9112         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9113         myLastCreatedElems.Append(newElem);
9114         if ( aShapeId && newElem )
9115           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9116         n1 = 0;
9117         n2 = 1;
9118         n3 = 7;
9119       }
9120     }
9121     // create needed triangles using n1,n2,n3 and inserted nodes
9122     int nbn = 2 + aNodesToInsert.size();
9123     //const SMDS_MeshNode* aNodes[nbn];
9124     vector<const SMDS_MeshNode*> aNodes(nbn);
9125     aNodes[0] = nodes[n1];
9126     aNodes[nbn-1] = nodes[n2];
9127     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9128     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9129       aNodes[iNode++] = *nIt;
9130     }
9131     for(i=1; i<nbn; i++) {
9132       SMDS_MeshElement* newElem =
9133         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9134       myLastCreatedElems.Append(newElem);
9135       if ( aShapeId && newElem )
9136         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9137     }
9138   }
9139   // remove old face
9140   aMesh->RemoveElement(theFace);
9141 }
9142
9143 //=======================================================================
9144 //function : UpdateVolumes
9145 //purpose  :
9146 //=======================================================================
9147 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9148                                       const SMDS_MeshNode*        theBetweenNode2,
9149                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9150 {
9151   myLastCreatedElems.Clear();
9152   myLastCreatedNodes.Clear();
9153
9154   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9155   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9156     const SMDS_MeshElement* elem = invElemIt->next();
9157
9158     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9159     SMDS_VolumeTool aVolume (elem);
9160     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9161       continue;
9162
9163     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9164     int iface, nbFaces = aVolume.NbFaces();
9165     vector<const SMDS_MeshNode *> poly_nodes;
9166     vector<int> quantities (nbFaces);
9167
9168     for (iface = 0; iface < nbFaces; iface++) {
9169       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9170       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9171       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9172
9173       for (int inode = 0; inode < nbFaceNodes; inode++) {
9174         poly_nodes.push_back(faceNodes[inode]);
9175
9176         if (nbInserted == 0) {
9177           if (faceNodes[inode] == theBetweenNode1) {
9178             if (faceNodes[inode + 1] == theBetweenNode2) {
9179               nbInserted = theNodesToInsert.size();
9180
9181               // add nodes to insert
9182               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9183               for (; nIt != theNodesToInsert.end(); nIt++) {
9184                 poly_nodes.push_back(*nIt);
9185               }
9186             }
9187           }
9188           else if (faceNodes[inode] == theBetweenNode2) {
9189             if (faceNodes[inode + 1] == theBetweenNode1) {
9190               nbInserted = theNodesToInsert.size();
9191
9192               // add nodes to insert in reversed order
9193               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9194               nIt--;
9195               for (; nIt != theNodesToInsert.begin(); nIt--) {
9196                 poly_nodes.push_back(*nIt);
9197               }
9198               poly_nodes.push_back(*nIt);
9199             }
9200           }
9201           else {
9202           }
9203         }
9204       }
9205       quantities[iface] = nbFaceNodes + nbInserted;
9206     }
9207
9208     // Replace or update the volume
9209     SMESHDS_Mesh *aMesh = GetMeshDS();
9210
9211     if (elem->IsPoly()) {
9212       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9213
9214     }
9215     else {
9216       int aShapeId = FindShape( elem );
9217
9218       SMDS_MeshElement* newElem =
9219         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9220       myLastCreatedElems.Append(newElem);
9221       if (aShapeId && newElem)
9222         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9223
9224       aMesh->RemoveElement(elem);
9225     }
9226   }
9227 }
9228
9229 //=======================================================================
9230 /*!
9231  * \brief Convert elements contained in a submesh to quadratic
9232  * \return int - nb of checked elements
9233  */
9234 //=======================================================================
9235
9236 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9237                                              SMESH_MesherHelper& theHelper,
9238                                              const bool          theForce3d)
9239 {
9240   int nbElem = 0;
9241   if( !theSm ) return nbElem;
9242
9243   vector<int> nbNodeInFaces;
9244   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9245   while(ElemItr->more())
9246   {
9247     nbElem++;
9248     const SMDS_MeshElement* elem = ElemItr->next();
9249     if( !elem || elem->IsQuadratic() ) continue;
9250
9251     int id = elem->GetID();
9252     int nbNodes = elem->NbNodes();
9253     SMDSAbs_ElementType aType = elem->GetType();
9254
9255     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9256     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9257       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9258
9259     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9260
9261     const SMDS_MeshElement* NewElem = 0;
9262
9263     switch( aType )
9264     {
9265     case SMDSAbs_Edge :
9266       {
9267         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9268         break;
9269       }
9270     case SMDSAbs_Face :
9271       {
9272         switch(nbNodes)
9273         {
9274         case 3:
9275           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9276           break;
9277         case 4:
9278           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9279           break;
9280         default:
9281           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9282           continue;
9283         }
9284         break;
9285       }
9286     case SMDSAbs_Volume :
9287       {
9288         switch(nbNodes)
9289         {
9290         case 4:
9291           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9292           break;
9293         case 5:
9294           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9295           break;
9296         case 6:
9297           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9298           break;
9299         case 8:
9300           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9301                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9302           break;
9303         default:
9304           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9305         }
9306         break;
9307       }
9308     default :
9309       continue;
9310     }
9311     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9312     if( NewElem )
9313       theSm->AddElement( NewElem );
9314   }
9315 //  if (!GetMeshDS()->isCompacted())
9316 //    GetMeshDS()->compactMesh();
9317   return nbElem;
9318 }
9319
9320 //=======================================================================
9321 //function : ConvertToQuadratic
9322 //purpose  :
9323 //=======================================================================
9324 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9325 {
9326   SMESHDS_Mesh* meshDS = GetMeshDS();
9327
9328   SMESH_MesherHelper aHelper(*myMesh);
9329   aHelper.SetIsQuadratic( true );
9330
9331   int nbCheckedElems = 0;
9332   if ( myMesh->HasShapeToMesh() )
9333   {
9334     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9335     {
9336       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9337       while ( smIt->more() ) {
9338         SMESH_subMesh* sm = smIt->next();
9339         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9340           aHelper.SetSubShape( sm->GetSubShape() );
9341           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9342         }
9343       }
9344     }
9345   }
9346   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9347   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9348   {
9349     SMESHDS_SubMesh *smDS = 0;
9350     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9351     while(aEdgeItr->more())
9352     {
9353       const SMDS_MeshEdge* edge = aEdgeItr->next();
9354       if(edge && !edge->IsQuadratic())
9355       {
9356         int id = edge->GetID();
9357         //MESSAGE("edge->GetID() " << id);
9358         const SMDS_MeshNode* n1 = edge->GetNode(0);
9359         const SMDS_MeshNode* n2 = edge->GetNode(1);
9360
9361         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9362
9363         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9364         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9365       }
9366     }
9367     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9368     while(aFaceItr->more())
9369     {
9370       const SMDS_MeshFace* face = aFaceItr->next();
9371       if(!face || face->IsQuadratic() ) continue;
9372
9373       int id = face->GetID();
9374       int nbNodes = face->NbNodes();
9375       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9376
9377       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9378
9379       SMDS_MeshFace * NewFace = 0;
9380       switch(nbNodes)
9381       {
9382       case 3:
9383         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9384         break;
9385       case 4:
9386         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9387         break;
9388       default:
9389         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9390       }
9391       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9392     }
9393     vector<int> nbNodeInFaces;
9394     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9395     while(aVolumeItr->more())
9396     {
9397       const SMDS_MeshVolume* volume = aVolumeItr->next();
9398       if(!volume || volume->IsQuadratic() ) continue;
9399
9400       int id = volume->GetID();
9401       int nbNodes = volume->NbNodes();
9402       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9403       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9404         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9405
9406       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9407
9408       SMDS_MeshVolume * NewVolume = 0;
9409       switch(nbNodes)
9410       {
9411       case 4:
9412         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9413                                       nodes[3], id, theForce3d );
9414         break;
9415       case 5:
9416         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9417                                       nodes[3], nodes[4], id, theForce3d);
9418         break;
9419       case 6:
9420         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9421                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9422         break;
9423       case 8:
9424         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9425                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9426         break;
9427       default:
9428         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9429       }
9430       ReplaceElemInGroups(volume, NewVolume, meshDS);
9431     }
9432   }
9433
9434   if ( !theForce3d )
9435   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9436     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9437     aHelper.FixQuadraticElements();
9438   }
9439 }
9440
9441 //================================================================================
9442 /*!
9443  * \brief Makes given elements quadratic
9444  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9445  *  \param theElements - elements to make quadratic 
9446  */
9447 //================================================================================
9448
9449 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9450                                           TIDSortedElemSet& theElements)
9451 {
9452   if ( theElements.empty() ) return;
9453
9454   // we believe that all theElements are of the same type
9455   SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9456   
9457   // get all nodes shared by theElements
9458   TIDSortedNodeSet allNodes;
9459   TIDSortedElemSet::iterator eIt = theElements.begin();
9460   for ( ; eIt != theElements.end(); ++eIt )
9461     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9462
9463   // complete theElements with elements of lower dim whose all nodes are in allNodes
9464
9465   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9466   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9467   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9468   for ( ; nIt != allNodes.end(); ++nIt )
9469   {
9470     const SMDS_MeshNode* n = *nIt;
9471     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9472     while ( invIt->more() )
9473     {
9474       const SMDS_MeshElement* e = invIt->next();
9475       if ( e->IsQuadratic() )
9476       {
9477         quadAdjacentElems[ e->GetType() ].insert( e );
9478         continue;
9479       }
9480       if ( e->GetType() >= elemType )
9481       {
9482         continue; // same type of more complex linear element
9483       }
9484
9485       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9486         continue; // e is already checked
9487
9488       // check nodes
9489       bool allIn = true;
9490       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9491       while ( nodeIt->more() && allIn )
9492         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9493       if ( allIn )
9494         theElements.insert(e );
9495     }
9496   }
9497
9498   SMESH_MesherHelper helper(*myMesh);
9499   helper.SetIsQuadratic( true );
9500
9501   // add links of quadratic adjacent elements to the helper
9502
9503   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9504     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9505           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9506     {
9507       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9508     }
9509   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9510     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9511           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9512     {
9513       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9514     }
9515   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9516     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9517           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9518     {
9519       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9520     }
9521
9522   // make quadratic elements instead of linear ones
9523
9524   SMESHDS_Mesh* meshDS = GetMeshDS();
9525   SMESHDS_SubMesh* smDS = 0;
9526   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9527   {
9528     const SMDS_MeshElement* elem = *eIt;
9529     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9530       continue;
9531
9532     int id = elem->GetID();
9533     SMDSAbs_ElementType type = elem->GetType();
9534     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9535
9536     if ( !smDS || !smDS->Contains( elem ))
9537       smDS = meshDS->MeshElements( elem->getshapeId() );
9538     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9539
9540     SMDS_MeshElement * newElem = 0;
9541     switch( nodes.size() )
9542     {
9543     case 4: // cases for most multiple element types go first (for optimization)
9544       if ( type == SMDSAbs_Volume )
9545         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9546       else
9547         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9548       break;
9549     case 8:
9550       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9551                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9552       break;
9553     case 3:
9554       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9555       break;
9556     case 2:
9557       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9558       break;
9559     case 5:
9560       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9561                                  nodes[4], id, theForce3d);
9562       break;
9563     case 6:
9564       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9565                                  nodes[4], nodes[5], id, theForce3d);
9566       break;
9567     default:;
9568     }
9569     ReplaceElemInGroups( elem, newElem, meshDS);
9570     if( newElem && smDS )
9571       smDS->AddElement( newElem );
9572   }
9573
9574   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9575   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9576     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9577     helper.FixQuadraticElements();
9578   }
9579 }
9580
9581 //=======================================================================
9582 /*!
9583  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9584  * \return int - nb of checked elements
9585  */
9586 //=======================================================================
9587
9588 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9589                                      SMDS_ElemIteratorPtr theItr,
9590                                      const int            theShapeID)
9591 {
9592   int nbElem = 0;
9593   SMESHDS_Mesh* meshDS = GetMeshDS();
9594
9595   while( theItr->more() )
9596   {
9597     const SMDS_MeshElement* elem = theItr->next();
9598     nbElem++;
9599     if( elem && elem->IsQuadratic())
9600     {
9601       int id                    = elem->GetID();
9602       int nbCornerNodes         = elem->NbCornerNodes();
9603       SMDSAbs_ElementType aType = elem->GetType();
9604
9605       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9606
9607       //remove a quadratic element
9608       if ( !theSm || !theSm->Contains( elem ))
9609         theSm = meshDS->MeshElements( elem->getshapeId() );
9610       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9611
9612       // remove medium nodes
9613       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9614         if ( nodes[i]->NbInverseElements() == 0 )
9615           meshDS->RemoveFreeNode( nodes[i], theSm );
9616
9617       // add a linear element
9618       nodes.resize( nbCornerNodes );
9619       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9620       ReplaceElemInGroups(elem, newElem, meshDS);
9621       if( theSm && newElem )
9622         theSm->AddElement( newElem );
9623     }
9624   }
9625   return nbElem;
9626 }
9627
9628 //=======================================================================
9629 //function : ConvertFromQuadratic
9630 //purpose  :
9631 //=======================================================================
9632
9633 bool SMESH_MeshEditor::ConvertFromQuadratic()
9634 {
9635   int nbCheckedElems = 0;
9636   if ( myMesh->HasShapeToMesh() )
9637   {
9638     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9639     {
9640       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9641       while ( smIt->more() ) {
9642         SMESH_subMesh* sm = smIt->next();
9643         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9644           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9645       }
9646     }
9647   }
9648
9649   int totalNbElems =
9650     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9651   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9652   {
9653     SMESHDS_SubMesh *aSM = 0;
9654     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9655   }
9656
9657   return true;
9658 }
9659
9660 namespace
9661 {
9662   //================================================================================
9663   /*!
9664    * \brief Return true if all medium nodes of the element are in the node set
9665    */
9666   //================================================================================
9667
9668   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9669   {
9670     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9671       if ( !nodeSet.count( elem->GetNode(i) ))
9672         return false;
9673     return true;
9674   }
9675 }
9676
9677 //================================================================================
9678 /*!
9679  * \brief Makes given elements linear
9680  */
9681 //================================================================================
9682
9683 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9684 {
9685   if ( theElements.empty() ) return;
9686
9687   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9688   set<int> mediumNodeIDs;
9689   TIDSortedElemSet::iterator eIt = theElements.begin();
9690   for ( ; eIt != theElements.end(); ++eIt )
9691   {
9692     const SMDS_MeshElement* e = *eIt;
9693     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9694       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9695   }
9696
9697   // replace given elements by linear ones
9698   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9699   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9700   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9701
9702   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9703   // except those elements sharing medium nodes of quadratic element whose medium nodes
9704   // are not all in mediumNodeIDs
9705
9706   // get remaining medium nodes
9707   TIDSortedNodeSet mediumNodes;
9708   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9709   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9710     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9711       mediumNodes.insert( mediumNodes.end(), n );
9712
9713   // find more quadratic elements to convert
9714   TIDSortedElemSet moreElemsToConvert;
9715   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9716   for ( ; nIt != mediumNodes.end(); ++nIt )
9717   {
9718     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9719     while ( invIt->more() )
9720     {
9721       const SMDS_MeshElement* e = invIt->next();
9722       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9723       {
9724         // find a more complex element including e and
9725         // whose medium nodes are not in mediumNodes
9726         bool complexFound = false;
9727         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9728         {
9729           SMDS_ElemIteratorPtr invIt2 =
9730             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9731           while ( invIt2->more() )
9732           {
9733             const SMDS_MeshElement* eComplex = invIt2->next();
9734             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9735             {
9736               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9737               if ( nbCommonNodes == e->NbNodes())
9738               {
9739                 complexFound = true;
9740                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9741                 break;
9742               }
9743             }
9744           }
9745         }
9746         if ( !complexFound )
9747           moreElemsToConvert.insert( e );
9748       }
9749     }
9750   }
9751   elemIt = SMDS_ElemIteratorPtr
9752     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9753   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9754 }
9755
9756 //=======================================================================
9757 //function : SewSideElements
9758 //purpose  :
9759 //=======================================================================
9760
9761 SMESH_MeshEditor::Sew_Error
9762 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9763                                    TIDSortedElemSet&    theSide2,
9764                                    const SMDS_MeshNode* theFirstNode1,
9765                                    const SMDS_MeshNode* theFirstNode2,
9766                                    const SMDS_MeshNode* theSecondNode1,
9767                                    const SMDS_MeshNode* theSecondNode2)
9768 {
9769   myLastCreatedElems.Clear();
9770   myLastCreatedNodes.Clear();
9771
9772   MESSAGE ("::::SewSideElements()");
9773   if ( theSide1.size() != theSide2.size() )
9774     return SEW_DIFF_NB_OF_ELEMENTS;
9775
9776   Sew_Error aResult = SEW_OK;
9777   // Algo:
9778   // 1. Build set of faces representing each side
9779   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9780   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9781
9782   // =======================================================================
9783   // 1. Build set of faces representing each side:
9784   // =======================================================================
9785   // a. build set of nodes belonging to faces
9786   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9787   // c. create temporary faces representing side of volumes if correspondent
9788   //    face does not exist
9789
9790   SMESHDS_Mesh* aMesh = GetMeshDS();
9791   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9792   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9793   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9794   set<const SMDS_MeshElement*> volSet1,  volSet2;
9795   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9796   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9797   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9798   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9799   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9800   int iSide, iFace, iNode;
9801
9802   list<const SMDS_MeshElement* > tempFaceList;
9803   for ( iSide = 0; iSide < 2; iSide++ ) {
9804     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9805     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9806     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9807     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9808     set<const SMDS_MeshElement*>::iterator vIt;
9809     TIDSortedElemSet::iterator eIt;
9810     set<const SMDS_MeshNode*>::iterator    nIt;
9811
9812     // check that given nodes belong to given elements
9813     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9814     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9815     int firstIndex = -1, secondIndex = -1;
9816     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9817       const SMDS_MeshElement* elem = *eIt;
9818       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9819       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9820       if ( firstIndex > -1 && secondIndex > -1 ) break;
9821     }
9822     if ( firstIndex < 0 || secondIndex < 0 ) {
9823       // we can simply return until temporary faces created
9824       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9825     }
9826
9827     // -----------------------------------------------------------
9828     // 1a. Collect nodes of existing faces
9829     //     and build set of face nodes in order to detect missing
9830     //     faces corresponding to sides of volumes
9831     // -----------------------------------------------------------
9832
9833     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9834
9835     // loop on the given element of a side
9836     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9837       //const SMDS_MeshElement* elem = *eIt;
9838       const SMDS_MeshElement* elem = *eIt;
9839       if ( elem->GetType() == SMDSAbs_Face ) {
9840         faceSet->insert( elem );
9841         set <const SMDS_MeshNode*> faceNodeSet;
9842         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9843         while ( nodeIt->more() ) {
9844           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9845           nodeSet->insert( n );
9846           faceNodeSet.insert( n );
9847         }
9848         setOfFaceNodeSet.insert( faceNodeSet );
9849       }
9850       else if ( elem->GetType() == SMDSAbs_Volume )
9851         volSet->insert( elem );
9852     }
9853     // ------------------------------------------------------------------------------
9854     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9855     // ------------------------------------------------------------------------------
9856
9857     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9858       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9859       while ( fIt->more() ) { // loop on faces sharing a node
9860         const SMDS_MeshElement* f = fIt->next();
9861         if ( faceSet->find( f ) == faceSet->end() ) {
9862           // check if all nodes are in nodeSet and
9863           // complete setOfFaceNodeSet if they are
9864           set <const SMDS_MeshNode*> faceNodeSet;
9865           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9866           bool allInSet = true;
9867           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9868             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9869             if ( nodeSet->find( n ) == nodeSet->end() )
9870               allInSet = false;
9871             else
9872               faceNodeSet.insert( n );
9873           }
9874           if ( allInSet ) {
9875             faceSet->insert( f );
9876             setOfFaceNodeSet.insert( faceNodeSet );
9877           }
9878         }
9879       }
9880     }
9881
9882     // -------------------------------------------------------------------------
9883     // 1c. Create temporary faces representing sides of volumes if correspondent
9884     //     face does not exist
9885     // -------------------------------------------------------------------------
9886
9887     if ( !volSet->empty() ) {
9888       //int nodeSetSize = nodeSet->size();
9889
9890       // loop on given volumes
9891       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9892         SMDS_VolumeTool vol (*vIt);
9893         // loop on volume faces: find free faces
9894         // --------------------------------------
9895         list<const SMDS_MeshElement* > freeFaceList;
9896         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9897           if ( !vol.IsFreeFace( iFace ))
9898             continue;
9899           // check if there is already a face with same nodes in a face set
9900           const SMDS_MeshElement* aFreeFace = 0;
9901           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9902           int nbNodes = vol.NbFaceNodes( iFace );
9903           set <const SMDS_MeshNode*> faceNodeSet;
9904           vol.GetFaceNodes( iFace, faceNodeSet );
9905           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9906           if ( isNewFace ) {
9907             // no such a face is given but it still can exist, check it
9908             if ( nbNodes == 3 ) {
9909               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9910             }
9911             else if ( nbNodes == 4 ) {
9912               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9913             }
9914             else {
9915               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9916               aFreeFace = aMesh->FindFace(poly_nodes);
9917             }
9918           }
9919           if ( !aFreeFace ) {
9920             // create a temporary face
9921             if ( nbNodes == 3 ) {
9922               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9923               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9924             }
9925             else if ( nbNodes == 4 ) {
9926               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9927               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9928             }
9929             else {
9930               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9931               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9932               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9933             }
9934           }
9935           if ( aFreeFace ) {
9936             freeFaceList.push_back( aFreeFace );
9937             tempFaceList.push_back( aFreeFace );
9938           }
9939
9940         } // loop on faces of a volume
9941
9942         // choose one of several free faces
9943         // --------------------------------------
9944         if ( freeFaceList.size() > 1 ) {
9945           // choose a face having max nb of nodes shared by other elems of a side
9946           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9947           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9948           while ( fIt != freeFaceList.end() ) { // loop on free faces
9949             int nbSharedNodes = 0;
9950             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9951             while ( nodeIt->more() ) { // loop on free face nodes
9952               const SMDS_MeshNode* n =
9953                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9954               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9955               while ( invElemIt->more() ) {
9956                 const SMDS_MeshElement* e = invElemIt->next();
9957                 if ( faceSet->find( e ) != faceSet->end() )
9958                   nbSharedNodes++;
9959                 if ( elemSet->find( e ) != elemSet->end() )
9960                   nbSharedNodes++;
9961               }
9962             }
9963             if ( nbSharedNodes >= maxNbNodes ) {
9964               maxNbNodes = nbSharedNodes;
9965               fIt++;
9966             }
9967             else
9968               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9969           }
9970           if ( freeFaceList.size() > 1 )
9971           {
9972             // could not choose one face, use another way
9973             // choose a face most close to the bary center of the opposite side
9974             gp_XYZ aBC( 0., 0., 0. );
9975             set <const SMDS_MeshNode*> addedNodes;
9976             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9977             eIt = elemSet2->begin();
9978             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9979               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9980               while ( nodeIt->more() ) { // loop on free face nodes
9981                 const SMDS_MeshNode* n =
9982                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9983                 if ( addedNodes.insert( n ).second )
9984                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9985               }
9986             }
9987             aBC /= addedNodes.size();
9988             double minDist = DBL_MAX;
9989             fIt = freeFaceList.begin();
9990             while ( fIt != freeFaceList.end() ) { // loop on free faces
9991               double dist = 0;
9992               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9993               while ( nodeIt->more() ) { // loop on free face nodes
9994                 const SMDS_MeshNode* n =
9995                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9996                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9997                 dist += ( aBC - p ).SquareModulus();
9998               }
9999               if ( dist < minDist ) {
10000                 minDist = dist;
10001                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
10002               }
10003               else
10004                 fIt = freeFaceList.erase( fIt++ );
10005             }
10006           }
10007         } // choose one of several free faces of a volume
10008
10009         if ( freeFaceList.size() == 1 ) {
10010           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
10011           faceSet->insert( aFreeFace );
10012           // complete a node set with nodes of a found free face
10013           //           for ( iNode = 0; iNode < ; iNode++ )
10014           //             nodeSet->insert( fNodes[ iNode ] );
10015         }
10016
10017       } // loop on volumes of a side
10018
10019       //       // complete a set of faces if new nodes in a nodeSet appeared
10020       //       // ----------------------------------------------------------
10021       //       if ( nodeSetSize != nodeSet->size() ) {
10022       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10023       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10024       //           while ( fIt->more() ) { // loop on faces sharing a node
10025       //             const SMDS_MeshElement* f = fIt->next();
10026       //             if ( faceSet->find( f ) == faceSet->end() ) {
10027       //               // check if all nodes are in nodeSet and
10028       //               // complete setOfFaceNodeSet if they are
10029       //               set <const SMDS_MeshNode*> faceNodeSet;
10030       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10031       //               bool allInSet = true;
10032       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10033       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10034       //                 if ( nodeSet->find( n ) == nodeSet->end() )
10035       //                   allInSet = false;
10036       //                 else
10037       //                   faceNodeSet.insert( n );
10038       //               }
10039       //               if ( allInSet ) {
10040       //                 faceSet->insert( f );
10041       //                 setOfFaceNodeSet.insert( faceNodeSet );
10042       //               }
10043       //             }
10044       //           }
10045       //         }
10046       //       }
10047     } // Create temporary faces, if there are volumes given
10048   } // loop on sides
10049
10050   if ( faceSet1.size() != faceSet2.size() ) {
10051     // delete temporary faces: they are in reverseElements of actual nodes
10052 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10053 //    while ( tmpFaceIt->more() )
10054 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10055 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10056 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10057 //      aMesh->RemoveElement(*tmpFaceIt);
10058     MESSAGE("Diff nb of faces");
10059     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10060   }
10061
10062   // ============================================================
10063   // 2. Find nodes to merge:
10064   //              bind a node to remove to a node to put instead
10065   // ============================================================
10066
10067   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10068   if ( theFirstNode1 != theFirstNode2 )
10069     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10070   if ( theSecondNode1 != theSecondNode2 )
10071     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10072
10073   LinkID_Gen aLinkID_Gen( GetMeshDS() );
10074   set< long > linkIdSet; // links to process
10075   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10076
10077   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10078   list< NLink > linkList[2];
10079   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10080   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10081   // loop on links in linkList; find faces by links and append links
10082   // of the found faces to linkList
10083   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10084   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10085     NLink link[] = { *linkIt[0], *linkIt[1] };
10086     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10087     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10088       continue;
10089
10090     // by links, find faces in the face sets,
10091     // and find indices of link nodes in the found faces;
10092     // in a face set, there is only one or no face sharing a link
10093     // ---------------------------------------------------------------
10094
10095     const SMDS_MeshElement* face[] = { 0, 0 };
10096     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10097     vector<const SMDS_MeshNode*> fnodes1(9);
10098     vector<const SMDS_MeshNode*> fnodes2(9);
10099     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10100     vector<const SMDS_MeshNode*> notLinkNodes1(6);
10101     vector<const SMDS_MeshNode*> notLinkNodes2(6);
10102     int iLinkNode[2][2];
10103     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10104       const SMDS_MeshNode* n1 = link[iSide].first;
10105       const SMDS_MeshNode* n2 = link[iSide].second;
10106       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10107       set< const SMDS_MeshElement* > fMap;
10108       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10109         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10110         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10111         while ( fIt->more() ) { // loop on faces sharing a node
10112           const SMDS_MeshElement* f = fIt->next();
10113           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10114               ! fMap.insert( f ).second ) // f encounters twice
10115           {
10116             if ( face[ iSide ] ) {
10117               MESSAGE( "2 faces per link " );
10118               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10119               break;
10120             }
10121             face[ iSide ] = f;
10122             faceSet->erase( f );
10123             // get face nodes and find ones of a link
10124             iNode = 0;
10125             int nbl = -1;
10126             if(f->IsPoly()) {
10127               if(iSide==0) {
10128                 fnodes1.resize(f->NbNodes()+1);
10129                 notLinkNodes1.resize(f->NbNodes()-2);
10130               }
10131               else {
10132                 fnodes2.resize(f->NbNodes()+1);
10133                 notLinkNodes2.resize(f->NbNodes()-2);
10134               }
10135             }
10136             if(!f->IsQuadratic()) {
10137               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10138               while ( nIt->more() ) {
10139                 const SMDS_MeshNode* n =
10140                   static_cast<const SMDS_MeshNode*>( nIt->next() );
10141                 if ( n == n1 ) {
10142                   iLinkNode[ iSide ][ 0 ] = iNode;
10143                 }
10144                 else if ( n == n2 ) {
10145                   iLinkNode[ iSide ][ 1 ] = iNode;
10146                 }
10147                 //else if ( notLinkNodes[ iSide ][ 0 ] )
10148                 //  notLinkNodes[ iSide ][ 1 ] = n;
10149                 //else
10150                 //  notLinkNodes[ iSide ][ 0 ] = n;
10151                 else {
10152                   nbl++;
10153                   if(iSide==0)
10154                     notLinkNodes1[nbl] = n;
10155                   //notLinkNodes1.push_back(n);
10156                   else
10157                     notLinkNodes2[nbl] = n;
10158                   //notLinkNodes2.push_back(n);
10159                 }
10160                 //faceNodes[ iSide ][ iNode++ ] = n;
10161                 if(iSide==0) {
10162                   fnodes1[iNode++] = n;
10163                 }
10164                 else {
10165                   fnodes2[iNode++] = n;
10166                 }
10167               }
10168             }
10169             else { // f->IsQuadratic()
10170               const SMDS_VtkFace* F =
10171                 dynamic_cast<const SMDS_VtkFace*>(f);
10172               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10173               // use special nodes iterator
10174               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10175               while ( anIter->more() ) {
10176                 const SMDS_MeshNode* n =
10177                   static_cast<const SMDS_MeshNode*>( anIter->next() );
10178                 if ( n == n1 ) {
10179                   iLinkNode[ iSide ][ 0 ] = iNode;
10180                 }
10181                 else if ( n == n2 ) {
10182                   iLinkNode[ iSide ][ 1 ] = iNode;
10183                 }
10184                 else {
10185                   nbl++;
10186                   if(iSide==0) {
10187                     notLinkNodes1[nbl] = n;
10188                   }
10189                   else {
10190                     notLinkNodes2[nbl] = n;
10191                   }
10192                 }
10193                 if(iSide==0) {
10194                   fnodes1[iNode++] = n;
10195                 }
10196                 else {
10197                   fnodes2[iNode++] = n;
10198                 }
10199               }
10200             }
10201             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10202             if(iSide==0) {
10203               fnodes1[iNode] = fnodes1[0];
10204             }
10205             else {
10206               fnodes2[iNode] = fnodes1[0];
10207             }
10208           }
10209         }
10210       }
10211     }
10212
10213     // check similarity of elements of the sides
10214     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10215       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10216       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10217         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10218       }
10219       else {
10220         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10221       }
10222       break; // do not return because it s necessary to remove tmp faces
10223     }
10224
10225     // set nodes to merge
10226     // -------------------
10227
10228     if ( face[0] && face[1] )  {
10229       int nbNodes = face[0]->NbNodes();
10230       if ( nbNodes != face[1]->NbNodes() ) {
10231         MESSAGE("Diff nb of face nodes");
10232         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10233         break; // do not return because it s necessary to remove tmp faces
10234       }
10235       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10236       if ( nbNodes == 3 ) {
10237         //nReplaceMap.insert( TNodeNodeMap::value_type
10238         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10239         nReplaceMap.insert( TNodeNodeMap::value_type
10240                             ( notLinkNodes1[0], notLinkNodes2[0] ));
10241       }
10242       else {
10243         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10244           // analyse link orientation in faces
10245           int i1 = iLinkNode[ iSide ][ 0 ];
10246           int i2 = iLinkNode[ iSide ][ 1 ];
10247           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10248           // if notLinkNodes are the first and the last ones, then
10249           // their order does not correspond to the link orientation
10250           if (( i1 == 1 && i2 == 2 ) ||
10251               ( i1 == 2 && i2 == 1 ))
10252             reverse[ iSide ] = !reverse[ iSide ];
10253         }
10254         if ( reverse[0] == reverse[1] ) {
10255           //nReplaceMap.insert( TNodeNodeMap::value_type
10256           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10257           //nReplaceMap.insert( TNodeNodeMap::value_type
10258           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10259           for(int nn=0; nn<nbNodes-2; nn++) {
10260             nReplaceMap.insert( TNodeNodeMap::value_type
10261                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10262           }
10263         }
10264         else {
10265           //nReplaceMap.insert( TNodeNodeMap::value_type
10266           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10267           //nReplaceMap.insert( TNodeNodeMap::value_type
10268           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10269           for(int nn=0; nn<nbNodes-2; nn++) {
10270             nReplaceMap.insert( TNodeNodeMap::value_type
10271                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10272           }
10273         }
10274       }
10275
10276       // add other links of the faces to linkList
10277       // -----------------------------------------
10278
10279       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10280       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10281         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10282         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10283         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10284         if ( !iter_isnew.second ) { // already in a set: no need to process
10285           linkIdSet.erase( iter_isnew.first );
10286         }
10287         else // new in set == encountered for the first time: add
10288         {
10289           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10290           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10291           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10292           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10293           linkList[0].push_back ( NLink( n1, n2 ));
10294           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10295         }
10296       }
10297     } // 2 faces found
10298   } // loop on link lists
10299
10300   if ( aResult == SEW_OK &&
10301        ( linkIt[0] != linkList[0].end() ||
10302          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10303     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10304              " " << (faceSetPtr[1]->empty()));
10305     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10306   }
10307
10308   // ====================================================================
10309   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10310   // ====================================================================
10311
10312   // delete temporary faces: they are in reverseElements of actual nodes
10313 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10314 //  while ( tmpFaceIt->more() )
10315 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10316 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10317 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10318 //    aMesh->RemoveElement(*tmpFaceIt);
10319
10320   if ( aResult != SEW_OK)
10321     return aResult;
10322
10323   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10324   // loop on nodes replacement map
10325   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10326   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10327     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10328       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10329       nodeIDsToRemove.push_back( nToRemove->GetID() );
10330       // loop on elements sharing nToRemove
10331       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10332       while ( invElemIt->more() ) {
10333         const SMDS_MeshElement* e = invElemIt->next();
10334         // get a new suite of nodes: make replacement
10335         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10336         vector< const SMDS_MeshNode*> nodes( nbNodes );
10337         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10338         while ( nIt->more() ) {
10339           const SMDS_MeshNode* n =
10340             static_cast<const SMDS_MeshNode*>( nIt->next() );
10341           nnIt = nReplaceMap.find( n );
10342           if ( nnIt != nReplaceMap.end() ) {
10343             nbReplaced++;
10344             n = (*nnIt).second;
10345           }
10346           nodes[ i++ ] = n;
10347         }
10348         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10349         //         elemIDsToRemove.push_back( e->GetID() );
10350         //       else
10351         if ( nbReplaced )
10352           {
10353             SMDSAbs_ElementType etyp = e->GetType();
10354             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10355             if (newElem)
10356               {
10357                 myLastCreatedElems.Append(newElem);
10358                 AddToSameGroups(newElem, e, aMesh);
10359                 int aShapeId = e->getshapeId();
10360                 if ( aShapeId )
10361                   {
10362                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10363                   }
10364               }
10365             aMesh->RemoveElement(e);
10366           }
10367       }
10368     }
10369
10370   Remove( nodeIDsToRemove, true );
10371
10372   return aResult;
10373 }
10374
10375 //================================================================================
10376 /*!
10377  * \brief Find corresponding nodes in two sets of faces
10378  * \param theSide1 - first face set
10379  * \param theSide2 - second first face
10380  * \param theFirstNode1 - a boundary node of set 1
10381  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10382  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10383  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10384  * \param nReplaceMap - output map of corresponding nodes
10385  * \return bool  - is a success or not
10386  */
10387 //================================================================================
10388
10389 #ifdef _DEBUG_
10390 //#define DEBUG_MATCHING_NODES
10391 #endif
10392
10393 SMESH_MeshEditor::Sew_Error
10394 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10395                                     set<const SMDS_MeshElement*>& theSide2,
10396                                     const SMDS_MeshNode*          theFirstNode1,
10397                                     const SMDS_MeshNode*          theFirstNode2,
10398                                     const SMDS_MeshNode*          theSecondNode1,
10399                                     const SMDS_MeshNode*          theSecondNode2,
10400                                     TNodeNodeMap &                nReplaceMap)
10401 {
10402   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10403
10404   nReplaceMap.clear();
10405   if ( theFirstNode1 != theFirstNode2 )
10406     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10407   if ( theSecondNode1 != theSecondNode2 )
10408     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10409
10410   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10411   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10412
10413   list< NLink > linkList[2];
10414   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10415   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10416
10417   // loop on links in linkList; find faces by links and append links
10418   // of the found faces to linkList
10419   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10420   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10421     NLink link[] = { *linkIt[0], *linkIt[1] };
10422     if ( linkSet.find( link[0] ) == linkSet.end() )
10423       continue;
10424
10425     // by links, find faces in the face sets,
10426     // and find indices of link nodes in the found faces;
10427     // in a face set, there is only one or no face sharing a link
10428     // ---------------------------------------------------------------
10429
10430     const SMDS_MeshElement* face[] = { 0, 0 };
10431     list<const SMDS_MeshNode*> notLinkNodes[2];
10432     //bool reverse[] = { false, false }; // order of notLinkNodes
10433     int nbNodes[2];
10434     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10435     {
10436       const SMDS_MeshNode* n1 = link[iSide].first;
10437       const SMDS_MeshNode* n2 = link[iSide].second;
10438       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10439       set< const SMDS_MeshElement* > facesOfNode1;
10440       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10441       {
10442         // during a loop of the first node, we find all faces around n1,
10443         // during a loop of the second node, we find one face sharing both n1 and n2
10444         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10445         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10446         while ( fIt->more() ) { // loop on faces sharing a node
10447           const SMDS_MeshElement* f = fIt->next();
10448           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10449               ! facesOfNode1.insert( f ).second ) // f encounters twice
10450           {
10451             if ( face[ iSide ] ) {
10452               MESSAGE( "2 faces per link " );
10453               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10454             }
10455             face[ iSide ] = f;
10456             faceSet->erase( f );
10457
10458             // get not link nodes
10459             int nbN = f->NbNodes();
10460             if ( f->IsQuadratic() )
10461               nbN /= 2;
10462             nbNodes[ iSide ] = nbN;
10463             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10464             int i1 = f->GetNodeIndex( n1 );
10465             int i2 = f->GetNodeIndex( n2 );
10466             int iEnd = nbN, iBeg = -1, iDelta = 1;
10467             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10468             if ( reverse ) {
10469               std::swap( iEnd, iBeg ); iDelta = -1;
10470             }
10471             int i = i2;
10472             while ( true ) {
10473               i += iDelta;
10474               if ( i == iEnd ) i = iBeg + iDelta;
10475               if ( i == i1 ) break;
10476               nodes.push_back ( f->GetNode( i ) );
10477             }
10478           }
10479         }
10480       }
10481     }
10482     // check similarity of elements of the sides
10483     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10484       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10485       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10486         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10487       }
10488       else {
10489         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10490       }
10491     }
10492
10493     // set nodes to merge
10494     // -------------------
10495
10496     if ( face[0] && face[1] )  {
10497       if ( nbNodes[0] != nbNodes[1] ) {
10498         MESSAGE("Diff nb of face nodes");
10499         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10500       }
10501 #ifdef DEBUG_MATCHING_NODES
10502       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10503                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10504                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10505 #endif
10506       int nbN = nbNodes[0];
10507       {
10508         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10509         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10510         for ( int i = 0 ; i < nbN - 2; ++i ) {
10511 #ifdef DEBUG_MATCHING_NODES
10512           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10513 #endif
10514           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10515         }
10516       }
10517
10518       // add other links of the face 1 to linkList
10519       // -----------------------------------------
10520
10521       const SMDS_MeshElement* f0 = face[0];
10522       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10523       for ( int i = 0; i < nbN; i++ )
10524       {
10525         const SMDS_MeshNode* n2 = f0->GetNode( i );
10526         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10527           linkSet.insert( SMESH_TLink( n1, n2 ));
10528         if ( !iter_isnew.second ) { // already in a set: no need to process
10529           linkSet.erase( iter_isnew.first );
10530         }
10531         else // new in set == encountered for the first time: add
10532         {
10533 #ifdef DEBUG_MATCHING_NODES
10534           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10535                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10536 #endif
10537           linkList[0].push_back ( NLink( n1, n2 ));
10538           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10539         }
10540         n1 = n2;
10541       }
10542     } // 2 faces found
10543   } // loop on link lists
10544
10545   return SEW_OK;
10546 }
10547
10548 //================================================================================
10549 /*!
10550   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10551   \param theElems - the list of elements (edges or faces) to be replicated
10552   The nodes for duplication could be found from these elements
10553   \param theNodesNot - list of nodes to NOT replicate
10554   \param theAffectedElems - the list of elements (cells and edges) to which the 
10555   replicated nodes should be associated to.
10556   \return TRUE if operation has been completed successfully, FALSE otherwise
10557 */
10558 //================================================================================
10559
10560 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10561                                     const TIDSortedElemSet& theNodesNot,
10562                                     const TIDSortedElemSet& theAffectedElems )
10563 {
10564   myLastCreatedElems.Clear();
10565   myLastCreatedNodes.Clear();
10566
10567   if ( theElems.size() == 0 )
10568     return false;
10569
10570   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10571   if ( !aMeshDS )
10572     return false;
10573
10574   bool res = false;
10575   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10576   // duplicate elements and nodes
10577   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10578   // replce nodes by duplications
10579   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10580   return res;
10581 }
10582
10583 //================================================================================
10584 /*!
10585   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10586   \param theMeshDS - mesh instance
10587   \param theElems - the elements replicated or modified (nodes should be changed)
10588   \param theNodesNot - nodes to NOT replicate
10589   \param theNodeNodeMap - relation of old node to new created node
10590   \param theIsDoubleElem - flag os to replicate element or modify
10591   \return TRUE if operation has been completed successfully, FALSE otherwise
10592 */
10593 //================================================================================
10594
10595 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10596                                     const TIDSortedElemSet& theElems,
10597                                     const TIDSortedElemSet& theNodesNot,
10598                                     std::map< const SMDS_MeshNode*,
10599                                     const SMDS_MeshNode* >& theNodeNodeMap,
10600                                     const bool theIsDoubleElem )
10601 {
10602   MESSAGE("doubleNodes");
10603   // iterate on through element and duplicate them (by nodes duplication)
10604   bool res = false;
10605   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10606   for ( ;  elemItr != theElems.end(); ++elemItr )
10607   {
10608     const SMDS_MeshElement* anElem = *elemItr;
10609     if (!anElem)
10610       continue;
10611
10612     bool isDuplicate = false;
10613     // duplicate nodes to duplicate element
10614     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10615     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10616     int ind = 0;
10617     while ( anIter->more() ) 
10618     { 
10619
10620       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10621       SMDS_MeshNode* aNewNode = aCurrNode;
10622       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10623         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10624       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10625       {
10626         // duplicate node
10627         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10628         theNodeNodeMap[ aCurrNode ] = aNewNode;
10629         myLastCreatedNodes.Append( aNewNode );
10630       }
10631       isDuplicate |= (aCurrNode != aNewNode);
10632       newNodes[ ind++ ] = aNewNode;
10633     }
10634     if ( !isDuplicate )
10635       continue;
10636
10637     if ( theIsDoubleElem )
10638       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10639     else
10640       {
10641       MESSAGE("ChangeElementNodes");
10642       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10643       }
10644     res = true;
10645   }
10646   return res;
10647 }
10648
10649 //================================================================================
10650 /*!
10651   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10652   \param theNodes - identifiers of nodes to be doubled
10653   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10654          nodes. If list of element identifiers is empty then nodes are doubled but 
10655          they not assigned to elements
10656   \return TRUE if operation has been completed successfully, FALSE otherwise
10657 */
10658 //================================================================================
10659
10660 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10661                                     const std::list< int >& theListOfModifiedElems )
10662 {
10663   MESSAGE("DoubleNodes");
10664   myLastCreatedElems.Clear();
10665   myLastCreatedNodes.Clear();
10666
10667   if ( theListOfNodes.size() == 0 )
10668     return false;
10669
10670   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10671   if ( !aMeshDS )
10672     return false;
10673
10674   // iterate through nodes and duplicate them
10675
10676   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10677
10678   std::list< int >::const_iterator aNodeIter;
10679   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10680   {
10681     int aCurr = *aNodeIter;
10682     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10683     if ( !aNode )
10684       continue;
10685
10686     // duplicate node
10687
10688     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10689     if ( aNewNode )
10690     {
10691       anOldNodeToNewNode[ aNode ] = aNewNode;
10692       myLastCreatedNodes.Append( aNewNode );
10693     }
10694   }
10695
10696   // Create map of new nodes for modified elements
10697
10698   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10699
10700   std::list< int >::const_iterator anElemIter;
10701   for ( anElemIter = theListOfModifiedElems.begin(); 
10702         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10703   {
10704     int aCurr = *anElemIter;
10705     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10706     if ( !anElem )
10707       continue;
10708
10709     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10710
10711     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10712     int ind = 0;
10713     while ( anIter->more() ) 
10714     { 
10715       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10716       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10717       {
10718         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10719         aNodeArr[ ind++ ] = aNewNode;
10720       }
10721       else
10722         aNodeArr[ ind++ ] = aCurrNode;
10723     }
10724     anElemToNodes[ anElem ] = aNodeArr;
10725   }
10726
10727   // Change nodes of elements  
10728
10729   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10730     anElemToNodesIter = anElemToNodes.begin();
10731   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10732   {
10733     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10734     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10735     if ( anElem )
10736       {
10737       MESSAGE("ChangeElementNodes");
10738       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10739       }
10740   }
10741
10742   return true;
10743 }
10744
10745 namespace {
10746
10747   //================================================================================
10748   /*!
10749   \brief Check if element located inside shape
10750   \return TRUE if IN or ON shape, FALSE otherwise
10751   */
10752   //================================================================================
10753
10754   template<class Classifier>
10755   bool isInside(const SMDS_MeshElement* theElem,
10756                 Classifier&             theClassifier,
10757                 const double            theTol)
10758   {
10759     gp_XYZ centerXYZ (0, 0, 0);
10760     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10761     while (aNodeItr->more())
10762       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10763
10764     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10765     theClassifier.Perform(aPnt, theTol);
10766     TopAbs_State aState = theClassifier.State();
10767     return (aState == TopAbs_IN || aState == TopAbs_ON );
10768   }
10769
10770   //================================================================================
10771   /*!
10772    * \brief Classifier of the 3D point on the TopoDS_Face
10773    *        with interaface suitable for isInside()
10774    */
10775   //================================================================================
10776
10777   struct _FaceClassifier
10778   {
10779     Extrema_ExtPS       _extremum;
10780     BRepAdaptor_Surface _surface;
10781     TopAbs_State        _state;
10782
10783     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10784     {
10785       _extremum.Initialize( _surface,
10786                             _surface.FirstUParameter(), _surface.LastUParameter(),
10787                             _surface.FirstVParameter(), _surface.LastVParameter(),
10788                             _surface.Tolerance(), _surface.Tolerance() );
10789     }
10790     void Perform(const gp_Pnt& aPnt, double theTol)
10791     {
10792       _state = TopAbs_OUT;
10793       _extremum.Perform(aPnt);
10794       if ( _extremum.IsDone() )
10795         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10796           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10797     }
10798     TopAbs_State State() const
10799     {
10800       return _state;
10801     }
10802   };
10803 }
10804
10805 //================================================================================
10806 /*!
10807   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10808   \param theElems - group of of elements (edges or faces) to be replicated
10809   \param theNodesNot - group of nodes not to replicate
10810   \param theShape - shape to detect affected elements (element which geometric center
10811   located on or inside shape).
10812   The replicated nodes should be associated to affected elements.
10813   \return TRUE if operation has been completed successfully, FALSE otherwise
10814 */
10815 //================================================================================
10816
10817 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10818                                             const TIDSortedElemSet& theNodesNot,
10819                                             const TopoDS_Shape&     theShape )
10820 {
10821   if ( theShape.IsNull() )
10822     return false;
10823
10824   const double aTol = Precision::Confusion();
10825   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10826   auto_ptr<_FaceClassifier>              aFaceClassifier;
10827   if ( theShape.ShapeType() == TopAbs_SOLID )
10828   {
10829     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10830     bsc3d->PerformInfinitePoint(aTol);
10831   }
10832   else if (theShape.ShapeType() == TopAbs_FACE )
10833   {
10834     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10835   }
10836
10837   // iterates on indicated elements and get elements by back references from their nodes
10838   TIDSortedElemSet anAffected;
10839   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10840   for ( ;  elemItr != theElems.end(); ++elemItr )
10841   {
10842     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10843     if (!anElem)
10844       continue;
10845
10846     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10847     while ( nodeItr->more() )
10848     {
10849       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10850       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10851         continue;
10852       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10853       while ( backElemItr->more() )
10854       {
10855         const SMDS_MeshElement* curElem = backElemItr->next();
10856         if ( curElem && theElems.find(curElem) == theElems.end() &&
10857              ( bsc3d.get() ?
10858                isInside( curElem, *bsc3d, aTol ) :
10859                isInside( curElem, *aFaceClassifier, aTol )))
10860           anAffected.insert( curElem );
10861       }
10862     }
10863   }
10864   return DoubleNodes( theElems, theNodesNot, anAffected );
10865 }
10866
10867 /*!
10868  *  \brief compute an oriented angle between two planes defined by four points.
10869  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10870  *  @param p0 base of the rotation axe
10871  *  @param p1 extremity of the rotation axe
10872  *  @param g1 belongs to the first plane
10873  *  @param g2 belongs to the second plane
10874  */
10875 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10876 {
10877 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10878 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10879 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10880 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10881   gp_Vec vref(p0, p1);
10882   gp_Vec v1(p0, g1);
10883   gp_Vec v2(p0, g2);
10884   gp_Vec n1 = vref.Crossed(v1);
10885   gp_Vec n2 = vref.Crossed(v2);
10886   return n2.AngleWithRef(n1, vref);
10887 }
10888
10889 /*!
10890  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10891  * The list of groups must describe a partition of the mesh volumes.
10892  * The nodes of the internal faces at the boundaries of the groups are doubled.
10893  * In option, the internal faces are replaced by flat elements.
10894  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10895  * The flat elements are stored in groups of volumes.
10896  * @param theElems - list of groups of volumes, where a group of volume is a set of
10897  * SMDS_MeshElements sorted by Id.
10898  * @param createJointElems - if TRUE, create the elements
10899  * @return TRUE if operation has been completed successfully, FALSE otherwise
10900  */
10901 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10902                                                      bool createJointElems)
10903 {
10904   MESSAGE("----------------------------------------------");
10905   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10906   MESSAGE("----------------------------------------------");
10907
10908   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10909   meshDS->BuildDownWardConnectivity(true);
10910   CHRONO(50);
10911   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10912
10913   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10914   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10915   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10916
10917   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10918   std::map<int,int>celldom; // cell vtkId --> domain
10919   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10920   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10921   faceDomains.clear();
10922   celldom.clear();
10923   cellDomains.clear();
10924   nodeDomains.clear();
10925   std::map<int,int> emptyMap;
10926   std::set<int> emptySet;
10927   emptyMap.clear();
10928
10929   for (int idom = 0; idom < theElems.size(); idom++)
10930     {
10931
10932       // --- build a map (face to duplicate --> volume to modify)
10933       //     with all the faces shared by 2 domains (group of elements)
10934       //     and corresponding volume of this domain, for each shared face.
10935       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10936
10937       const TIDSortedElemSet& domain = theElems[idom];
10938       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10939       for (; elemItr != domain.end(); ++elemItr)
10940         {
10941           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10942           if (!anElem)
10943             continue;
10944           int vtkId = anElem->getVtkId();
10945           int neighborsVtkIds[NBMAXNEIGHBORS];
10946           int downIds[NBMAXNEIGHBORS];
10947           unsigned char downTypes[NBMAXNEIGHBORS];
10948           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10949           for (int n = 0; n < nbNeighbors; n++)
10950             {
10951               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10952               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10953               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10954                 {
10955                   DownIdType face(downIds[n], downTypes[n]);
10956                   if (!faceDomains.count(face))
10957                     faceDomains[face] = emptyMap; // create an empty entry for face
10958                   if (!faceDomains[face].count(idom))
10959                     {
10960                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10961                       celldom[vtkId] = idom;
10962                     }
10963                 }
10964             }
10965         }
10966     }
10967
10968   //MESSAGE("Number of shared faces " << faceDomains.size());
10969   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10970
10971   // --- explore the shared faces domain by domain,
10972   //     explore the nodes of the face and see if they belong to a cell in the domain,
10973   //     which has only a node or an edge on the border (not a shared face)
10974
10975   for (int idomain = 0; idomain < theElems.size(); idomain++)
10976     {
10977       const TIDSortedElemSet& domain = theElems[idomain];
10978       itface = faceDomains.begin();
10979       for (; itface != faceDomains.end(); ++itface)
10980         {
10981           std::map<int, int> domvol = itface->second;
10982           if (!domvol.count(idomain))
10983             continue;
10984           DownIdType face = itface->first;
10985           //MESSAGE(" --- face " << face.cellId);
10986           std::set<int> oldNodes;
10987           oldNodes.clear();
10988           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10989           std::set<int>::iterator itn = oldNodes.begin();
10990           for (; itn != oldNodes.end(); ++itn)
10991             {
10992               int oldId = *itn;
10993               //MESSAGE("     node " << oldId);
10994               std::set<int> cells;
10995               cells.clear();
10996               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10997               for (int i=0; i<l.ncells; i++)
10998                 {
10999                   int vtkId = l.cells[i];
11000                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
11001                   if (!domain.count(anElem))
11002                     continue;
11003                   int vtkType = grid->GetCellType(vtkId);
11004                   int downId = grid->CellIdToDownId(vtkId);
11005                   if (downId < 0)
11006                     {
11007                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
11008                       continue; // not OK at this stage of the algorithm:
11009                                 //no cells created after BuildDownWardConnectivity
11010                     }
11011                   DownIdType aCell(downId, vtkType);
11012                   if (celldom.count(vtkId))
11013                     continue;
11014                   cellDomains[aCell][idomain] = vtkId;
11015                   celldom[vtkId] = idomain;
11016                 }
11017             }
11018         }
11019     }
11020
11021   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
11022   //     for each shared face, get the nodes
11023   //     for each node, for each domain of the face, create a clone of the node
11024
11025   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
11026   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
11027   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
11028
11029   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
11030   std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
11031
11032   for (int idomain = 0; idomain < theElems.size(); idomain++)
11033     {
11034       itface = faceDomains.begin();
11035       for (; itface != faceDomains.end(); ++itface)
11036         {
11037           std::map<int, int> domvol = itface->second;
11038           if (!domvol.count(idomain))
11039             continue;
11040           DownIdType face = itface->first;
11041           //MESSAGE(" --- face " << face.cellId);
11042           std::set<int> oldNodes;
11043           oldNodes.clear();
11044           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11045           bool isMultipleDetected = false;
11046           std::set<int>::iterator itn = oldNodes.begin();
11047           for (; itn != oldNodes.end(); ++itn)
11048             {
11049               int oldId = *itn;
11050               //MESSAGE("     node " << oldId);
11051               if (!nodeDomains.count(oldId))
11052                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11053               if (nodeDomains[oldId].empty())
11054                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11055               std::map<int, int>::iterator itdom = domvol.begin();
11056               for (; itdom != domvol.end(); ++itdom)
11057                 {
11058                   int idom = itdom->first;
11059                   //MESSAGE("         domain " << idom);
11060                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
11061                     {
11062                       if (nodeDomains[oldId].size() >= 2) // a multiple node
11063                         {
11064                           vector<int> orderedDoms;
11065                           //MESSAGE("multiple node " << oldId);
11066                           isMultipleDetected =true;
11067                           if (mutipleNodes.count(oldId))
11068                             orderedDoms = mutipleNodes[oldId];
11069                           else
11070                             {
11071                               map<int,int>::iterator it = nodeDomains[oldId].begin();
11072                               for (; it != nodeDomains[oldId].end(); ++it)
11073                                 orderedDoms.push_back(it->first);
11074                             }
11075                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
11076                           //stringstream txt;
11077                           //for (int i=0; i<orderedDoms.size(); i++)
11078                           //  txt << orderedDoms[i] << " ";
11079                           //MESSAGE("orderedDoms " << txt.str());
11080                           mutipleNodes[oldId] = orderedDoms;
11081                         }
11082                       double *coords = grid->GetPoint(oldId);
11083                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11084                       int newId = newNode->getVtkId();
11085                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
11086                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11087                     }
11088                   if (nodeDomains[oldId].size() >= 3)
11089                     {
11090                       //MESSAGE("confirm multiple node " << oldId);
11091                       isMultipleDetected =true;
11092                     }
11093                 }
11094             }
11095           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11096             {
11097               //MESSAGE("multiple Nodes detected on a shared face");
11098               int downId = itface->first.cellId;
11099               unsigned char cellType = itface->first.cellType;
11100               int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11101               const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11102               const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11103               for (int ie =0; ie < nbEdges; ie++)
11104                 {
11105                   int nodes[3];
11106                   int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11107                   if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11108                     {
11109                       vector<int> vn0 = mutipleNodes[nodes[0]];
11110                       vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11111                       sort( vn0.begin(), vn0.end() );
11112                       sort( vn1.begin(), vn1.end() );
11113                       if (vn0 == vn1)
11114                         {
11115                           //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11116                           double *coords = grid->GetPoint(nodes[0]);
11117                           gp_Pnt p0(coords[0], coords[1], coords[2]);
11118                           coords = grid->GetPoint(nodes[nbNodes - 1]);
11119                           gp_Pnt p1(coords[0], coords[1], coords[2]);
11120                           gp_Pnt gref;
11121                           int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11122                           map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11123                           map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11124                           int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11125                           for (int id=0; id < vn0.size(); id++)
11126                             {
11127                               int idom = vn0[id];
11128                               for (int ivol=0; ivol<nbvol; ivol++)
11129                                 {
11130                                   int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11131                                   SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11132                                   if (theElems[idom].count(elem))
11133                                     {
11134                                       SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11135                                       domvol[idom] = svol;
11136                                       //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11137                                       double values[3];
11138                                       vtkIdType npts = 0;
11139                                       vtkIdType* pts = 0;
11140                                       grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11141                                       SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11142                                       if (id ==0)
11143                                         {
11144                                           gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11145                                           angleDom[idom] = 0;
11146                                         }
11147                                       else
11148                                         {
11149                                           gp_Pnt g(values[0], values[1], values[2]);
11150                                           angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11151                                           //MESSAGE("  angle=" << angleDom[idom]);
11152                                         }
11153                                       break;
11154                                     }
11155                                 }
11156                             }
11157                           map<double, int> sortedDom; // sort domains by angle
11158                           for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11159                             sortedDom[ia->second] = ia->first;
11160                           vector<int> vnodes;
11161                           vector<int> vdom;
11162                           for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11163                             {
11164                               vdom.push_back(ib->second);
11165                               //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11166                             }
11167                           for (int ino = 0; ino < nbNodes; ino++)
11168                             vnodes.push_back(nodes[ino]);
11169                           edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11170                         }
11171                     }
11172                 }
11173             }
11174         }
11175     }
11176
11177   // --- iterate on shared faces (volumes to modify, face to extrude)
11178   //     get node id's of the face (id SMDS = id VTK)
11179   //     create flat element with old and new nodes if requested
11180
11181   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11182   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11183
11184   std::map<int, std::map<long,int> > nodeQuadDomains;
11185   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11186
11187   if (createJointElems)
11188     {
11189       itface = faceDomains.begin();
11190       for (; itface != faceDomains.end(); ++itface)
11191         {
11192           DownIdType face = itface->first;
11193           std::set<int> oldNodes;
11194           std::set<int>::iterator itn;
11195           oldNodes.clear();
11196           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11197
11198           std::map<int, int> domvol = itface->second;
11199           std::map<int, int>::iterator itdom = domvol.begin();
11200           int dom1 = itdom->first;
11201           int vtkVolId = itdom->second;
11202           itdom++;
11203           int dom2 = itdom->first;
11204           SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11205                                                              nodeQuadDomains);
11206           stringstream grpname;
11207           grpname << "j_";
11208           if (dom1 < dom2)
11209             grpname << dom1 << "_" << dom2;
11210           else
11211             grpname << dom2 << "_" << dom1;
11212           int idg;
11213           string namegrp = grpname.str();
11214           if (!mapOfJunctionGroups.count(namegrp))
11215             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11216           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11217           if (sgrp)
11218             sgrp->Add(vol->GetID());
11219         }
11220     }
11221
11222   // --- create volumes on multiple domain intersection if requested
11223   //     iterate on edgesMultiDomains
11224
11225   if (createJointElems)
11226     {
11227       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11228       for (; ite != edgesMultiDomains.end(); ++ite)
11229         {
11230           vector<int> nodes = ite->first;
11231           vector<int> orderDom = ite->second;
11232           vector<vtkIdType> orderedNodes;
11233           if (nodes.size() == 2)
11234             {
11235               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11236               for (int ino=0; ino < nodes.size(); ino++)
11237                 if (orderDom.size() == 3)
11238                   for (int idom = 0; idom <orderDom.size(); idom++)
11239                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11240                 else
11241                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11242                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11243               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11244
11245               stringstream grpname;
11246               grpname << "mj_";
11247               grpname << 0 << "_" << 0;
11248               int idg;
11249               string namegrp = grpname.str();
11250               if (!mapOfJunctionGroups.count(namegrp))
11251                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11252               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11253               if (sgrp)
11254                 sgrp->Add(vol->GetID());
11255             }
11256           else
11257             {
11258               //MESSAGE("Quadratic multiple joints not implemented");
11259               // TODO quadratic nodes
11260             }
11261         }
11262     }
11263
11264   // --- list the explicit faces and edges of the mesh that need to be modified,
11265   //     i.e. faces and edges built with one or more duplicated nodes.
11266   //     associate these faces or edges to their corresponding domain.
11267   //     only the first domain found is kept when a face or edge is shared
11268
11269   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11270   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11271   faceOrEdgeDom.clear();
11272   feDom.clear();
11273
11274   for (int idomain = 0; idomain < theElems.size(); idomain++)
11275     {
11276       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11277       for (; itnod != nodeDomains.end(); ++itnod)
11278         {
11279           int oldId = itnod->first;
11280           //MESSAGE("     node " << oldId);
11281           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11282           for (int i = 0; i < l.ncells; i++)
11283             {
11284               int vtkId = l.cells[i];
11285               int vtkType = grid->GetCellType(vtkId);
11286               int downId = grid->CellIdToDownId(vtkId);
11287               if (downId < 0)
11288                 continue; // new cells: not to be modified
11289               DownIdType aCell(downId, vtkType);
11290               int volParents[1000];
11291               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11292               for (int j = 0; j < nbvol; j++)
11293                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11294                   if (!feDom.count(vtkId))
11295                     {
11296                       feDom[vtkId] = idomain;
11297                       faceOrEdgeDom[aCell] = emptyMap;
11298                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11299                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11300                       //        << " type " << vtkType << " downId " << downId);
11301                     }
11302             }
11303         }
11304     }
11305
11306   // --- iterate on shared faces (volumes to modify, face to extrude)
11307   //     get node id's of the face
11308   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11309
11310   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11311   for (int m=0; m<3; m++)
11312     {
11313       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11314       itface = (*amap).begin();
11315       for (; itface != (*amap).end(); ++itface)
11316         {
11317           DownIdType face = itface->first;
11318           std::set<int> oldNodes;
11319           std::set<int>::iterator itn;
11320           oldNodes.clear();
11321           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11322           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11323           std::map<int, int> localClonedNodeIds;
11324
11325           std::map<int, int> domvol = itface->second;
11326           std::map<int, int>::iterator itdom = domvol.begin();
11327           for (; itdom != domvol.end(); ++itdom)
11328             {
11329               int idom = itdom->first;
11330               int vtkVolId = itdom->second;
11331               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11332               localClonedNodeIds.clear();
11333               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11334                 {
11335                   int oldId = *itn;
11336                   if (nodeDomains[oldId].count(idom))
11337                     {
11338                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11339                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11340                     }
11341                 }
11342               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11343             }
11344         }
11345     }
11346
11347   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11348   grid->BuildLinks();
11349
11350   CHRONOSTOP(50);
11351   counters::stats();
11352   return true;
11353 }
11354
11355 /*!
11356  * \brief Double nodes on some external faces and create flat elements.
11357  * Flat elements are mainly used by some types of mechanic calculations.
11358  *
11359  * Each group of the list must be constituted of faces.
11360  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11361  * @param theElems - list of groups of faces, where a group of faces is a set of
11362  * SMDS_MeshElements sorted by Id.
11363  * @return TRUE if operation has been completed successfully, FALSE otherwise
11364  */
11365 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11366 {
11367   MESSAGE("-------------------------------------------------");
11368   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11369   MESSAGE("-------------------------------------------------");
11370
11371   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11372
11373   // --- For each group of faces
11374   //     duplicate the nodes, create a flat element based on the face
11375   //     replace the nodes of the faces by their clones
11376
11377   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11378   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11379   clonedNodes.clear();
11380   intermediateNodes.clear();
11381   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11382   mapOfJunctionGroups.clear();
11383
11384   for (int idom = 0; idom < theElems.size(); idom++)
11385     {
11386       const TIDSortedElemSet& domain = theElems[idom];
11387       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11388       for (; elemItr != domain.end(); ++elemItr)
11389         {
11390           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11391           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11392           if (!aFace)
11393             continue;
11394           // MESSAGE("aFace=" << aFace->GetID());
11395           bool isQuad = aFace->IsQuadratic();
11396           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11397
11398           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11399
11400           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11401           while (nodeIt->more())
11402             {
11403               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11404               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11405               if (isMedium)
11406                 ln2.push_back(node);
11407               else
11408                 ln0.push_back(node);
11409
11410               const SMDS_MeshNode* clone = 0;
11411               if (!clonedNodes.count(node))
11412                 {
11413                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11414                   clonedNodes[node] = clone;
11415                 }
11416               else
11417                 clone = clonedNodes[node];
11418
11419               if (isMedium)
11420                 ln3.push_back(clone);
11421               else
11422                 ln1.push_back(clone);
11423
11424               const SMDS_MeshNode* inter = 0;
11425               if (isQuad && (!isMedium))
11426                 {
11427                   if (!intermediateNodes.count(node))
11428                     {
11429                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11430                       intermediateNodes[node] = inter;
11431                     }
11432                   else
11433                     inter = intermediateNodes[node];
11434                   ln4.push_back(inter);
11435                 }
11436             }
11437
11438           // --- extrude the face
11439
11440           vector<const SMDS_MeshNode*> ln;
11441           SMDS_MeshVolume* vol = 0;
11442           vtkIdType aType = aFace->GetVtkType();
11443           switch (aType)
11444           {
11445             case VTK_TRIANGLE:
11446               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11447               // MESSAGE("vol prism " << vol->GetID());
11448               ln.push_back(ln1[0]);
11449               ln.push_back(ln1[1]);
11450               ln.push_back(ln1[2]);
11451               break;
11452             case VTK_QUAD:
11453               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11454               // MESSAGE("vol hexa " << vol->GetID());
11455               ln.push_back(ln1[0]);
11456               ln.push_back(ln1[1]);
11457               ln.push_back(ln1[2]);
11458               ln.push_back(ln1[3]);
11459               break;
11460             case VTK_QUADRATIC_TRIANGLE:
11461               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11462                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11463               // MESSAGE("vol quad prism " << vol->GetID());
11464               ln.push_back(ln1[0]);
11465               ln.push_back(ln1[1]);
11466               ln.push_back(ln1[2]);
11467               ln.push_back(ln3[0]);
11468               ln.push_back(ln3[1]);
11469               ln.push_back(ln3[2]);
11470               break;
11471             case VTK_QUADRATIC_QUAD:
11472 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11473 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11474 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11475               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11476                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11477                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11478               // MESSAGE("vol quad hexa " << vol->GetID());
11479               ln.push_back(ln1[0]);
11480               ln.push_back(ln1[1]);
11481               ln.push_back(ln1[2]);
11482               ln.push_back(ln1[3]);
11483               ln.push_back(ln3[0]);
11484               ln.push_back(ln3[1]);
11485               ln.push_back(ln3[2]);
11486               ln.push_back(ln3[3]);
11487               break;
11488             case VTK_POLYGON:
11489               break;
11490             default:
11491               break;
11492           }
11493
11494           if (vol)
11495             {
11496               stringstream grpname;
11497               grpname << "jf_";
11498               grpname << idom;
11499               int idg;
11500               string namegrp = grpname.str();
11501               if (!mapOfJunctionGroups.count(namegrp))
11502                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11503               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11504               if (sgrp)
11505                 sgrp->Add(vol->GetID());
11506             }
11507
11508           // --- modify the face
11509
11510           aFace->ChangeNodes(&ln[0], ln.size());
11511         }
11512     }
11513   return true;
11514 }
11515
11516 //================================================================================
11517 /*!
11518  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11519  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11520  * \return TRUE if operation has been completed successfully, FALSE otherwise
11521  */
11522 //================================================================================
11523
11524 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11525 {
11526   // iterates on volume elements and detect all free faces on them
11527   SMESHDS_Mesh* aMesh = GetMeshDS();
11528   if (!aMesh)
11529     return false;
11530   //bool res = false;
11531   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11532   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11533   while(vIt->more())
11534   {
11535     const SMDS_MeshVolume* volume = vIt->next();
11536     SMDS_VolumeTool vTool( volume );
11537     vTool.SetExternalNormal();
11538     const bool isPoly = volume->IsPoly();
11539     const bool isQuad = volume->IsQuadratic();
11540     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11541     {
11542       if (!vTool.IsFreeFace(iface))
11543         continue;
11544       nbFree++;
11545       vector<const SMDS_MeshNode *> nodes;
11546       int nbFaceNodes = vTool.NbFaceNodes(iface);
11547       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11548       int inode = 0;
11549       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11550         nodes.push_back(faceNodes[inode]);
11551       if (isQuad)
11552         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11553           nodes.push_back(faceNodes[inode]);
11554
11555       // add new face based on volume nodes
11556       if (aMesh->FindFace( nodes ) ) {
11557         nbExisted++;
11558         continue; // face already exsist
11559       }
11560       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11561       nbCreated++;
11562     }
11563   }
11564   return ( nbFree==(nbExisted+nbCreated) );
11565 }
11566
11567 namespace
11568 {
11569   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11570   {
11571     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11572       return n;
11573     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11574   }
11575 }
11576 //================================================================================
11577 /*!
11578  * \brief Creates missing boundary elements
11579  *  \param elements - elements whose boundary is to be checked
11580  *  \param dimension - defines type of boundary elements to create
11581  *  \param group - a group to store created boundary elements in
11582  *  \param targetMesh - a mesh to store created boundary elements in
11583  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11584  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
11585  *                                boundary elements will be copied into the targetMesh
11586  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11587  *                                boundary elements will be added into the new group
11588  *  \param aroundElements - if true, elements will be created on boundary of given
11589  *                          elements else, on boundary of the whole mesh.
11590  * \return nb of added boundary elements
11591  */
11592 //================================================================================
11593
11594 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11595                                        Bnd_Dimension           dimension,
11596                                        SMESH_Group*            group/*=0*/,
11597                                        SMESH_Mesh*             targetMesh/*=0*/,
11598                                        bool                    toCopyElements/*=false*/,
11599                                        bool                    toCopyExistingBoundary/*=false*/,
11600                                        bool                    toAddExistingBondary/*= false*/,
11601                                        bool                    aroundElements/*= false*/)
11602 {
11603   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11604   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11605   // hope that all elements are of the same type, do not check them all
11606   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11607     throw SALOME_Exception(LOCALIZED("wrong element type"));
11608
11609   if ( !targetMesh )
11610     toCopyElements = toCopyExistingBoundary = false;
11611
11612   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11613   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11614   int nbAddedBnd = 0;
11615
11616   // editor adding present bnd elements and optionally holding elements to add to the group
11617   SMESH_MeshEditor* presentEditor;
11618   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11619   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11620
11621   SMDS_VolumeTool vTool;
11622   TIDSortedElemSet avoidSet;
11623   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11624   int inode;
11625
11626   typedef vector<const SMDS_MeshNode*> TConnectivity;
11627
11628   SMDS_ElemIteratorPtr eIt;
11629   if (elements.empty())
11630     eIt = aMesh->elementsIterator(elemType);
11631   else
11632     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11633
11634   while (eIt->more())
11635   {
11636     const SMDS_MeshElement* elem = eIt->next();
11637     const int iQuad = elem->IsQuadratic();
11638
11639     // ------------------------------------------------------------------------------------
11640     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11641     // ------------------------------------------------------------------------------------
11642     vector<const SMDS_MeshElement*> presentBndElems;
11643     vector<TConnectivity>           missingBndElems;
11644     TConnectivity nodes;
11645     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11646     {
11647       vTool.SetExternalNormal();
11648       const SMDS_MeshElement* otherVol = 0;
11649       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11650       {
11651         if ( !vTool.IsFreeFace(iface, &otherVol) &&
11652              ( !aroundElements || elements.count( otherVol )))
11653           continue;
11654         const int nbFaceNodes = vTool.NbFaceNodes(iface);
11655         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11656         if ( missType == SMDSAbs_Edge ) // boundary edges
11657         {
11658           nodes.resize( 2+iQuad );
11659           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11660           {
11661             for ( int j = 0; j < nodes.size(); ++j )
11662               nodes[j] =nn[i+j];
11663             if ( const SMDS_MeshElement* edge =
11664                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11665               presentBndElems.push_back( edge );
11666             else
11667               missingBndElems.push_back( nodes );
11668           }
11669         }
11670         else // boundary face
11671         {
11672           nodes.clear();
11673           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11674             nodes.push_back( nn[inode] );
11675           if (iQuad)
11676             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11677               nodes.push_back( nn[inode] );
11678
11679           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11680             presentBndElems.push_back( f );
11681           else
11682             missingBndElems.push_back( nodes );
11683
11684           if ( targetMesh != myMesh )
11685           {
11686             // add 1D elements on face boundary to be added to a new mesh
11687             const SMDS_MeshElement* edge;
11688             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11689             {
11690               if ( iQuad )
11691                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11692               else
11693                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11694               if ( edge && avoidSet.insert( edge ).second )
11695                 presentBndElems.push_back( edge );
11696             }
11697           }
11698         }
11699       }
11700     }
11701     else                     // elem is a face ------------------------------------------
11702     {
11703       avoidSet.clear(), avoidSet.insert( elem );
11704       int nbNodes = elem->NbCornerNodes();
11705       nodes.resize( 2 /*+ iQuad*/);
11706       for ( int i = 0; i < nbNodes; i++ )
11707       {
11708         nodes[0] = elem->GetNode(i);
11709         nodes[1] = elem->GetNode((i+1)%nbNodes);
11710         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11711           continue; // not free link
11712
11713         //if ( iQuad )
11714         //nodes[2] = elem->GetNode( i + nbNodes );
11715         if ( const SMDS_MeshElement* edge =
11716              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11717           presentBndElems.push_back( edge );
11718         else
11719           missingBndElems.push_back( nodes );
11720       }
11721     }
11722
11723     // ---------------------------------
11724     // 2. Add missing boundary elements
11725     // ---------------------------------
11726     if ( targetMesh != myMesh )
11727       // instead of making a map of nodes in this mesh and targetMesh,
11728       // we create nodes with same IDs.
11729       for ( int i = 0; i < missingBndElems.size(); ++i )
11730       {
11731         TConnectivity& srcNodes = missingBndElems[i];
11732         TConnectivity  nodes( srcNodes.size() );
11733         for ( inode = 0; inode < nodes.size(); ++inode )
11734           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11735         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11736                                                                    missType,
11737                                                                    /*noMedium=*/true))
11738           continue;
11739         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11740         ++nbAddedBnd;
11741       }
11742     else
11743       for ( int i = 0; i < missingBndElems.size(); ++i )
11744       {
11745         TConnectivity& nodes = missingBndElems[i];
11746         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11747                                                                    missType,
11748                                                                    /*noMedium=*/true))
11749           continue;
11750         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11751         ++nbAddedBnd;
11752       }
11753
11754     // ----------------------------------
11755     // 3. Copy present boundary elements
11756     // ----------------------------------
11757     if ( toCopyExistingBoundary )
11758       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11759       {
11760         const SMDS_MeshElement* e = presentBndElems[i];
11761         TConnectivity nodes( e->NbNodes() );
11762         for ( inode = 0; inode < nodes.size(); ++inode )
11763           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11764         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11765       }
11766     else // store present elements to add them to a group
11767       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11768       {
11769         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11770       }
11771       
11772   } // loop on given elements
11773
11774   // ---------------------------------------------
11775   // 4. Fill group with boundary elements
11776   // ---------------------------------------------
11777   if ( group )
11778   {
11779     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11780       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11781         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11782   }
11783   tgtEditor.myLastCreatedElems.Clear();
11784   tgtEditor2.myLastCreatedElems.Clear();
11785
11786   // -----------------------
11787   // 5. Copy given elements
11788   // -----------------------
11789   if ( toCopyElements && targetMesh != myMesh )
11790   {
11791     if (elements.empty())
11792       eIt = aMesh->elementsIterator(elemType);
11793     else
11794       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11795     while (eIt->more())
11796     {
11797       const SMDS_MeshElement* elem = eIt->next();
11798       TConnectivity nodes( elem->NbNodes() );
11799       for ( inode = 0; inode < nodes.size(); ++inode )
11800         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11801       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11802
11803       tgtEditor.myLastCreatedElems.Clear();
11804     }
11805   }
11806   return nbAddedBnd;
11807 }