Salome HOME
Fix for the issue "21356: EDF 1705 SMESH: Extrusion along a path using a mesh w/o...
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 // Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21
22 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
23 // File      : SMESH_MeshEditor.cxx
24 // Created   : Mon Apr 12 16:10:22 2004
25 // Author    : Edward AGAPOV (eap)
26
27 #define CHRONODEF
28 #include "SMESH_MeshEditor.hxx"
29
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_SpacePosition.hxx"
36 //#include "SMDS_QuadraticFaceOfNodes.hxx"
37 #include "SMDS_MeshGroup.hxx"
38 #include "SMDS_LinearEdge.hxx"
39 #include "SMDS_Downward.hxx"
40 #include "SMDS_SetIterator.hxx"
41
42 #include "SMESHDS_Group.hxx"
43 #include "SMESHDS_Mesh.hxx"
44
45 #include "SMESH_Algo.hxx"
46 #include "SMESH_ControlsDef.hxx"
47 #include "SMESH_Group.hxx"
48 #include "SMESH_MesherHelper.hxx"
49 #include "SMESH_OctreeNode.hxx"
50 #include "SMESH_subMesh.hxx"
51
52 #include <Basics_OCCTVersion.hxx>
53
54 #include "utilities.h"
55
56 #include <BRepAdaptor_Surface.hxx>
57 #include <BRepBuilderAPI_MakeEdge.hxx>
58 #include <BRepClass3d_SolidClassifier.hxx>
59 #include <BRep_Tool.hxx>
60 #include <ElCLib.hxx>
61 #include <Extrema_GenExtPS.hxx>
62 #include <Extrema_POnCurv.hxx>
63 #include <Extrema_POnSurf.hxx>
64 #include <GC_MakeSegment.hxx>
65 #include <Geom2d_Curve.hxx>
66 #include <GeomAPI_ExtremaCurveCurve.hxx>
67 #include <GeomAdaptor_Surface.hxx>
68 #include <Geom_Curve.hxx>
69 #include <Geom_Line.hxx>
70 #include <Geom_Surface.hxx>
71 #include <IntAna_IntConicQuad.hxx>
72 #include <IntAna_Quadric.hxx>
73 #include <Precision.hxx>
74 #include <TColStd_ListOfInteger.hxx>
75 #include <TopAbs_State.hxx>
76 #include <TopExp.hxx>
77 #include <TopExp_Explorer.hxx>
78 #include <TopTools_ListIteratorOfListOfShape.hxx>
79 #include <TopTools_ListOfShape.hxx>
80 #include <TopTools_SequenceOfShape.hxx>
81 #include <TopoDS.hxx>
82 #include <TopoDS_Face.hxx>
83 #include <gp.hxx>
84 #include <gp_Ax1.hxx>
85 #include <gp_Dir.hxx>
86 #include <gp_Lin.hxx>
87 #include <gp_Pln.hxx>
88 #include <gp_Trsf.hxx>
89 #include <gp_Vec.hxx>
90 #include <gp_XY.hxx>
91 #include <gp_XYZ.hxx>
92
93 #include <math.h>
94
95 #include <map>
96 #include <set>
97 #include <numeric>
98 #include <limits>
99 #include <algorithm>
100 #include <sstream>
101
102 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
103
104 using namespace std;
105 using namespace SMESH::Controls;
106
107 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
108 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
109
110 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
111
112 //=======================================================================
113 //function : SMESH_MeshEditor
114 //purpose  :
115 //=======================================================================
116
117 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
118   :myMesh( theMesh ) // theMesh may be NULL
119 {
120 }
121
122 //=======================================================================
123 /*!
124  * \brief Add element
125  */
126 //=======================================================================
127
128 SMDS_MeshElement*
129 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
130                              const SMDSAbs_ElementType            type,
131                              const bool                           isPoly,
132                              const int                            ID)
133 {
134   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
135   SMDS_MeshElement* e = 0;
136   int nbnode = node.size();
137   SMESHDS_Mesh* mesh = GetMeshDS();
138   switch ( type ) {
139   case SMDSAbs_Face:
140     if ( !isPoly ) {
141       if      (nbnode == 3) {
142         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
143         else           e = mesh->AddFace      (node[0], node[1], node[2] );
144       }
145       else if (nbnode == 4) {
146         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
147         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
148       }
149       else if (nbnode == 6) {
150         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
151                                                node[4], node[5], ID);
152         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
153                                                node[4], node[5] );
154       }
155       else if (nbnode == 8) {
156         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
157                                                node[4], node[5], node[6], node[7], ID);
158         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
159                                                node[4], node[5], node[6], node[7] );
160       }
161     } else {
162       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
163       else           e = mesh->AddPolygonalFace      (node    );
164     }
165     break;
166
167   case SMDSAbs_Volume:
168     if ( !isPoly ) {
169       if      (nbnode == 4) {
170         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
171         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
172       }
173       else if (nbnode == 5) {
174         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
175                                                  node[4], ID);
176         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
177                                                  node[4] );
178       }
179       else if (nbnode == 6) {
180         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
181                                                  node[4], node[5], ID);
182         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
183                                                  node[4], node[5] );
184       }
185       else if (nbnode == 8) {
186         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
187                                                  node[4], node[5], node[6], node[7], ID);
188         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
189                                                  node[4], node[5], node[6], node[7] );
190       }
191       else if (nbnode == 10) {
192         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
193                                                  node[4], node[5], node[6], node[7],
194                                                  node[8], node[9], ID);
195         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
196                                                  node[4], node[5], node[6], node[7],
197                                                  node[8], node[9] );
198       }
199       else if (nbnode == 13) {
200         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
201                                                  node[4], node[5], node[6], node[7],
202                                                  node[8], node[9], node[10],node[11],
203                                                  node[12],ID);
204         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
205                                                  node[4], node[5], node[6], node[7],
206                                                  node[8], node[9], node[10],node[11],
207                                                  node[12] );
208       }
209       else if (nbnode == 15) {
210         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
211                                                  node[4], node[5], node[6], node[7],
212                                                  node[8], node[9], node[10],node[11],
213                                                  node[12],node[13],node[14],ID);
214         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
215                                                  node[4], node[5], node[6], node[7],
216                                                  node[8], node[9], node[10],node[11],
217                                                  node[12],node[13],node[14] );
218       }
219       else if (nbnode == 20) {
220         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
221                                                  node[4], node[5], node[6], node[7],
222                                                  node[8], node[9], node[10],node[11],
223                                                  node[12],node[13],node[14],node[15],
224                                                  node[16],node[17],node[18],node[19],ID);
225         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
226                                                  node[4], node[5], node[6], node[7],
227                                                  node[8], node[9], node[10],node[11],
228                                                  node[12],node[13],node[14],node[15],
229                                                  node[16],node[17],node[18],node[19] );
230       }
231     }
232     break;
233
234   case SMDSAbs_Edge:
235     if ( nbnode == 2 ) {
236       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
237       else           e = mesh->AddEdge      (node[0], node[1] );
238     }
239     else if ( nbnode == 3 ) {
240       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
241       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
242     }
243     break;
244
245   case SMDSAbs_0DElement:
246     if ( nbnode == 1 ) {
247       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
248       else           e = mesh->Add0DElement      (node[0] );
249     }
250     break;
251
252   case SMDSAbs_Node:
253     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
254     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
255     break;
256
257   default:;
258   }
259   if ( e ) myLastCreatedElems.Append( e );
260   return e;
261 }
262
263 //=======================================================================
264 /*!
265  * \brief Add element
266  */
267 //=======================================================================
268
269 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
270                                                const SMDSAbs_ElementType type,
271                                                const bool                isPoly,
272                                                const int                 ID)
273 {
274   vector<const SMDS_MeshNode*> nodes;
275   nodes.reserve( nodeIDs.size() );
276   vector<int>::const_iterator id = nodeIDs.begin();
277   while ( id != nodeIDs.end() ) {
278     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
279       nodes.push_back( node );
280     else
281       return 0;
282   }
283   return AddElement( nodes, type, isPoly, ID );
284 }
285
286 //=======================================================================
287 //function : Remove
288 //purpose  : Remove a node or an element.
289 //           Modify a compute state of sub-meshes which become empty
290 //=======================================================================
291
292 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
293                               const bool         isNodes )
294 {
295   myLastCreatedElems.Clear();
296   myLastCreatedNodes.Clear();
297
298   SMESHDS_Mesh* aMesh = GetMeshDS();
299   set< SMESH_subMesh *> smmap;
300
301   int removed = 0;
302   list<int>::const_iterator it = theIDs.begin();
303   for ( ; it != theIDs.end(); it++ ) {
304     const SMDS_MeshElement * elem;
305     if ( isNodes )
306       elem = aMesh->FindNode( *it );
307     else
308       elem = aMesh->FindElement( *it );
309     if ( !elem )
310       continue;
311
312     // Notify VERTEX sub-meshes about modification
313     if ( isNodes ) {
314       const SMDS_MeshNode* node = cast2Node( elem );
315       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
316         if ( int aShapeID = node->getshapeId() )
317           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
318             smmap.insert( sm );
319     }
320     // Find sub-meshes to notify about modification
321     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
322     //     while ( nodeIt->more() ) {
323     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
324     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
325     //       if ( aPosition.get() ) {
326     //         if ( int aShapeID = aPosition->GetShapeId() ) {
327     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
328     //             smmap.insert( sm );
329     //         }
330     //       }
331     //     }
332
333     // Do remove
334     if ( isNodes )
335       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
336     else
337       aMesh->RemoveElement( elem );
338     removed++;
339   }
340
341   // Notify sub-meshes about modification
342   if ( !smmap.empty() ) {
343     set< SMESH_subMesh *>::iterator smIt;
344     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
345       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
346   }
347
348   //   // Check if the whole mesh becomes empty
349   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
350   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
351
352   return removed;
353 }
354
355 //=======================================================================
356 //function : FindShape
357 //purpose  : Return an index of the shape theElem is on
358 //           or zero if a shape not found
359 //=======================================================================
360
361 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
362 {
363   myLastCreatedElems.Clear();
364   myLastCreatedNodes.Clear();
365
366   SMESHDS_Mesh * aMesh = GetMeshDS();
367   if ( aMesh->ShapeToMesh().IsNull() )
368     return 0;
369
370   int aShapeID = theElem->getshapeId();
371   if ( aShapeID < 1 )
372     return 0;
373
374   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
375     if ( sm->Contains( theElem ))
376       return aShapeID;
377
378   if ( theElem->GetType() == SMDSAbs_Node ) {
379     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
380   }
381   else {
382     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
383   }
384
385   TopoDS_Shape aShape; // the shape a node of theElem is on
386   if ( theElem->GetType() != SMDSAbs_Node )
387   {
388     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
389     while ( nodeIt->more() ) {
390       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
391       if ((aShapeID = node->getshapeId()) > 0) {
392         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
393           if ( sm->Contains( theElem ))
394             return aShapeID;
395           if ( aShape.IsNull() )
396             aShape = aMesh->IndexToShape( aShapeID );
397         }
398       }
399     }
400   }
401
402   // None of nodes is on a proper shape,
403   // find the shape among ancestors of aShape on which a node is
404   if ( !aShape.IsNull() ) {
405     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
406     for ( ; ancIt.More(); ancIt.Next() ) {
407       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
408       if ( sm && sm->Contains( theElem ))
409         return aMesh->ShapeToIndex( ancIt.Value() );
410     }
411   }
412   else
413   {
414     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
415     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
416     for ( ; id_sm != id2sm.end(); ++id_sm )
417       if ( id_sm->second->Contains( theElem ))
418         return id_sm->first;
419   }
420
421   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
422   return 0;
423 }
424
425 //=======================================================================
426 //function : IsMedium
427 //purpose  :
428 //=======================================================================
429
430 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
431                                 const SMDSAbs_ElementType typeToCheck)
432 {
433   bool isMedium = false;
434   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
435   while (it->more() && !isMedium ) {
436     const SMDS_MeshElement* elem = it->next();
437     isMedium = elem->IsMediumNode(node);
438   }
439   return isMedium;
440 }
441
442 //=======================================================================
443 //function : ShiftNodesQuadTria
444 //purpose  : auxilary
445 //           Shift nodes in the array corresponded to quadratic triangle
446 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
447 //=======================================================================
448 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
449 {
450   const SMDS_MeshNode* nd1 = aNodes[0];
451   aNodes[0] = aNodes[1];
452   aNodes[1] = aNodes[2];
453   aNodes[2] = nd1;
454   const SMDS_MeshNode* nd2 = aNodes[3];
455   aNodes[3] = aNodes[4];
456   aNodes[4] = aNodes[5];
457   aNodes[5] = nd2;
458 }
459
460 //=======================================================================
461 //function : edgeConnectivity
462 //purpose  : auxilary 
463 //           return number of the edges connected with the theNode.
464 //           if theEdges has connections with the other type of the
465 //           elements, return -1 
466 //=======================================================================
467 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
468 {
469   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
470   int nb=0;
471   while(elemIt->more()) {
472     elemIt->next();
473     nb++;
474   }
475   return nb;
476 }
477
478
479 //=======================================================================
480 //function : GetNodesFromTwoTria
481 //purpose  : auxilary
482 //           Shift nodes in the array corresponded to quadratic triangle
483 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
484 //=======================================================================
485 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
486                                 const SMDS_MeshElement * theTria2,
487                                 const SMDS_MeshNode* N1[],
488                                 const SMDS_MeshNode* N2[])
489 {
490   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
491   int i=0;
492   while(i<6) {
493     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
494     i++;
495   }
496   if(it->more()) return false;
497   it = theTria2->nodesIterator();
498   i=0;
499   while(i<6) {
500     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
501     i++;
502   }
503   if(it->more()) return false;
504
505   int sames[3] = {-1,-1,-1};
506   int nbsames = 0;
507   int j;
508   for(i=0; i<3; i++) {
509     for(j=0; j<3; j++) {
510       if(N1[i]==N2[j]) {
511         sames[i] = j;
512         nbsames++;
513         break;
514       }
515     }
516   }
517   if(nbsames!=2) return false;
518   if(sames[0]>-1) {
519     ShiftNodesQuadTria(N1);
520     if(sames[1]>-1) {
521       ShiftNodesQuadTria(N1);
522     }
523   }
524   i = sames[0] + sames[1] + sames[2];
525   for(; i<2; i++) {
526     ShiftNodesQuadTria(N2);
527   }
528   // now we receive following N1 and N2 (using numeration as above image)
529   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
530   // i.e. first nodes from both arrays determ new diagonal
531   return true;
532 }
533
534 //=======================================================================
535 //function : InverseDiag
536 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
537 //           but having other common link.
538 //           Return False if args are improper
539 //=======================================================================
540
541 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
542                                     const SMDS_MeshElement * theTria2 )
543 {
544   MESSAGE("InverseDiag");
545   myLastCreatedElems.Clear();
546   myLastCreatedNodes.Clear();
547
548   if (!theTria1 || !theTria2)
549     return false;
550
551   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
552   if (!F1) return false;
553   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
554   if (!F2) return false;
555   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
556       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
557
558     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
559     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
560     //    |/ |                                         | \|
561     //  B +--+ 2                                     B +--+ 2
562
563     // put nodes in array and find out indices of the same ones
564     const SMDS_MeshNode* aNodes [6];
565     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
566     int i = 0;
567     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
568     while ( it->more() ) {
569       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
570
571       if ( i > 2 ) // theTria2
572         // find same node of theTria1
573         for ( int j = 0; j < 3; j++ )
574           if ( aNodes[ i ] == aNodes[ j ]) {
575             sameInd[ j ] = i;
576             sameInd[ i ] = j;
577             break;
578           }
579       // next
580       i++;
581       if ( i == 3 ) {
582         if ( it->more() )
583           return false; // theTria1 is not a triangle
584         it = theTria2->nodesIterator();
585       }
586       if ( i == 6 && it->more() )
587         return false; // theTria2 is not a triangle
588     }
589
590     // find indices of 1,2 and of A,B in theTria1
591     int iA = 0, iB = 0, i1 = 0, i2 = 0;
592     for ( i = 0; i < 6; i++ ) {
593       if ( sameInd [ i ] == 0 ) {
594         if ( i < 3 ) i1 = i;
595         else         i2 = i;
596       }
597       else if (i < 3) {
598         if ( iA ) iB = i;
599         else      iA = i;
600       }
601     }
602     // nodes 1 and 2 should not be the same
603     if ( aNodes[ i1 ] == aNodes[ i2 ] )
604       return false;
605
606     // theTria1: A->2
607     aNodes[ iA ] = aNodes[ i2 ];
608     // theTria2: B->1
609     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
610
611     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
612     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
613
614     return true;
615
616   } // end if(F1 && F2)
617
618   // check case of quadratic faces
619   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
620     return false;
621   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
622     return false;
623
624   //       5
625   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
626   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
627   //    |   / |
628   //  7 +  +  + 6
629   //    | /9  |
630   //    |/    |
631   //  4 +--+--+ 3
632   //       8
633
634   const SMDS_MeshNode* N1 [6];
635   const SMDS_MeshNode* N2 [6];
636   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
637     return false;
638   // now we receive following N1 and N2 (using numeration as above image)
639   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
640   // i.e. first nodes from both arrays determ new diagonal
641
642   const SMDS_MeshNode* N1new [6];
643   const SMDS_MeshNode* N2new [6];
644   N1new[0] = N1[0];
645   N1new[1] = N2[0];
646   N1new[2] = N2[1];
647   N1new[3] = N1[4];
648   N1new[4] = N2[3];
649   N1new[5] = N1[5];
650   N2new[0] = N1[0];
651   N2new[1] = N1[1];
652   N2new[2] = N2[0];
653   N2new[3] = N1[3];
654   N2new[4] = N2[5];
655   N2new[5] = N1[4];
656   // replaces nodes in faces
657   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
658   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
659
660   return true;
661 }
662
663 //=======================================================================
664 //function : findTriangles
665 //purpose  : find triangles sharing theNode1-theNode2 link
666 //=======================================================================
667
668 static bool findTriangles(const SMDS_MeshNode *    theNode1,
669                           const SMDS_MeshNode *    theNode2,
670                           const SMDS_MeshElement*& theTria1,
671                           const SMDS_MeshElement*& theTria2)
672 {
673   if ( !theNode1 || !theNode2 ) return false;
674
675   theTria1 = theTria2 = 0;
676
677   set< const SMDS_MeshElement* > emap;
678   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
679   while (it->more()) {
680     const SMDS_MeshElement* elem = it->next();
681     if ( elem->NbNodes() == 3 )
682       emap.insert( elem );
683   }
684   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
685   while (it->more()) {
686     const SMDS_MeshElement* elem = it->next();
687     if ( emap.find( elem ) != emap.end() ) {
688       if ( theTria1 ) {
689         // theTria1 must be element with minimum ID
690         if( theTria1->GetID() < elem->GetID() ) {
691           theTria2 = elem;
692         }
693         else {
694           theTria2 = theTria1;
695           theTria1 = elem;
696         }
697         break;
698       }
699       else {
700         theTria1 = elem;
701       }
702     }
703   }
704   return ( theTria1 && theTria2 );
705 }
706
707 //=======================================================================
708 //function : InverseDiag
709 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
710 //           with ones built on the same 4 nodes but having other common link.
711 //           Return false if proper faces not found
712 //=======================================================================
713
714 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
715                                     const SMDS_MeshNode * theNode2)
716 {
717   myLastCreatedElems.Clear();
718   myLastCreatedNodes.Clear();
719
720   MESSAGE( "::InverseDiag()" );
721
722   const SMDS_MeshElement *tr1, *tr2;
723   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
724     return false;
725
726   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
727   if (!F1) return false;
728   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
729   if (!F2) return false;
730   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
731       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
732
733     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
734     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
735     //    |/ |                                    | \|
736     //  B +--+ 2                                B +--+ 2
737
738     // put nodes in array
739     // and find indices of 1,2 and of A in tr1 and of B in tr2
740     int i, iA1 = 0, i1 = 0;
741     const SMDS_MeshNode* aNodes1 [3];
742     SMDS_ElemIteratorPtr it;
743     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
744       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
745       if ( aNodes1[ i ] == theNode1 )
746         iA1 = i; // node A in tr1
747       else if ( aNodes1[ i ] != theNode2 )
748         i1 = i;  // node 1
749     }
750     int iB2 = 0, i2 = 0;
751     const SMDS_MeshNode* aNodes2 [3];
752     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
753       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
754       if ( aNodes2[ i ] == theNode2 )
755         iB2 = i; // node B in tr2
756       else if ( aNodes2[ i ] != theNode1 )
757         i2 = i;  // node 2
758     }
759
760     // nodes 1 and 2 should not be the same
761     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
762       return false;
763
764     // tr1: A->2
765     aNodes1[ iA1 ] = aNodes2[ i2 ];
766     // tr2: B->1
767     aNodes2[ iB2 ] = aNodes1[ i1 ];
768
769     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
770     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
771
772     return true;
773   }
774
775   // check case of quadratic faces
776   return InverseDiag(tr1,tr2);
777 }
778
779 //=======================================================================
780 //function : getQuadrangleNodes
781 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
782 //           fusion of triangles tr1 and tr2 having shared link on
783 //           theNode1 and theNode2
784 //=======================================================================
785
786 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
787                         const SMDS_MeshNode *    theNode1,
788                         const SMDS_MeshNode *    theNode2,
789                         const SMDS_MeshElement * tr1,
790                         const SMDS_MeshElement * tr2 )
791 {
792   if( tr1->NbNodes() != tr2->NbNodes() )
793     return false;
794   // find the 4-th node to insert into tr1
795   const SMDS_MeshNode* n4 = 0;
796   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
797   int i=0;
798   while ( !n4 && i<3 ) {
799     const SMDS_MeshNode * n = cast2Node( it->next() );
800     i++;
801     bool isDiag = ( n == theNode1 || n == theNode2 );
802     if ( !isDiag )
803       n4 = n;
804   }
805   // Make an array of nodes to be in a quadrangle
806   int iNode = 0, iFirstDiag = -1;
807   it = tr1->nodesIterator();
808   i=0;
809   while ( i<3 ) {
810     const SMDS_MeshNode * n = cast2Node( it->next() );
811     i++;
812     bool isDiag = ( n == theNode1 || n == theNode2 );
813     if ( isDiag ) {
814       if ( iFirstDiag < 0 )
815         iFirstDiag = iNode;
816       else if ( iNode - iFirstDiag == 1 )
817         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
818     }
819     else if ( n == n4 ) {
820       return false; // tr1 and tr2 should not have all the same nodes
821     }
822     theQuadNodes[ iNode++ ] = n;
823   }
824   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
825     theQuadNodes[ iNode ] = n4;
826
827   return true;
828 }
829
830 //=======================================================================
831 //function : DeleteDiag
832 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
833 //           with a quadrangle built on the same 4 nodes.
834 //           Return false if proper faces not found
835 //=======================================================================
836
837 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
838                                    const SMDS_MeshNode * theNode2)
839 {
840   myLastCreatedElems.Clear();
841   myLastCreatedNodes.Clear();
842
843   MESSAGE( "::DeleteDiag()" );
844
845   const SMDS_MeshElement *tr1, *tr2;
846   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
847     return false;
848
849   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
850   if (!F1) return false;
851   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
852   if (!F2) return false;
853   SMESHDS_Mesh * aMesh = GetMeshDS();
854
855   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
856       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
857
858     const SMDS_MeshNode* aNodes [ 4 ];
859     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
860       return false;
861
862     const SMDS_MeshElement* newElem = 0;
863     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
864     myLastCreatedElems.Append(newElem);
865     AddToSameGroups( newElem, tr1, aMesh );
866     int aShapeId = tr1->getshapeId();
867     if ( aShapeId )
868       {
869         aMesh->SetMeshElementOnShape( newElem, aShapeId );
870       }
871     aMesh->RemoveElement( tr1 );
872     aMesh->RemoveElement( tr2 );
873
874     return true;
875   }
876
877   // check case of quadratic faces
878   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
879     return false;
880   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
881     return false;
882
883   //       5
884   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
885   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
886   //    |   / |
887   //  7 +  +  + 6
888   //    | /9  |
889   //    |/    |
890   //  4 +--+--+ 3
891   //       8
892
893   const SMDS_MeshNode* N1 [6];
894   const SMDS_MeshNode* N2 [6];
895   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
896     return false;
897   // now we receive following N1 and N2 (using numeration as above image)
898   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
899   // i.e. first nodes from both arrays determ new diagonal
900
901   const SMDS_MeshNode* aNodes[8];
902   aNodes[0] = N1[0];
903   aNodes[1] = N1[1];
904   aNodes[2] = N2[0];
905   aNodes[3] = N2[1];
906   aNodes[4] = N1[3];
907   aNodes[5] = N2[5];
908   aNodes[6] = N2[3];
909   aNodes[7] = N1[5];
910
911   const SMDS_MeshElement* newElem = 0;
912   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
913                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
914   myLastCreatedElems.Append(newElem);
915   AddToSameGroups( newElem, tr1, aMesh );
916   int aShapeId = tr1->getshapeId();
917   if ( aShapeId )
918     {
919       aMesh->SetMeshElementOnShape( newElem, aShapeId );
920     }
921   aMesh->RemoveElement( tr1 );
922   aMesh->RemoveElement( tr2 );
923
924   // remove middle node (9)
925   GetMeshDS()->RemoveNode( N1[4] );
926
927   return true;
928 }
929
930 //=======================================================================
931 //function : Reorient
932 //purpose  : Reverse theElement orientation
933 //=======================================================================
934
935 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
936 {
937   MESSAGE("Reorient");
938   myLastCreatedElems.Clear();
939   myLastCreatedNodes.Clear();
940
941   if (!theElem)
942     return false;
943   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
944   if ( !it || !it->more() )
945     return false;
946
947   switch ( theElem->GetType() ) {
948
949   case SMDSAbs_Edge:
950   case SMDSAbs_Face: {
951     if(!theElem->IsQuadratic()) {
952       int i = theElem->NbNodes();
953       vector<const SMDS_MeshNode*> aNodes( i );
954       while ( it->more() )
955         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
956       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
957     }
958     else {
959       // quadratic elements
960       if(theElem->GetType()==SMDSAbs_Edge) {
961         vector<const SMDS_MeshNode*> aNodes(3);
962         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
963         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
964         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
965         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
966       }
967       else {
968         int nbn = theElem->NbNodes();
969         vector<const SMDS_MeshNode*> aNodes(nbn);
970         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
971         int i=1;
972         for(; i<nbn/2; i++) {
973           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
974         }
975         for(i=0; i<nbn/2; i++) {
976           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
977         }
978         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
979       }
980     }
981   }
982   case SMDSAbs_Volume: {
983     if (theElem->IsPoly()) {
984       // TODO reorient vtk polyhedron
985       MESSAGE("reorient vtk polyhedron ?");
986       const SMDS_VtkVolume* aPolyedre =
987         dynamic_cast<const SMDS_VtkVolume*>( theElem );
988       if (!aPolyedre) {
989         MESSAGE("Warning: bad volumic element");
990         return false;
991       }
992
993       int nbFaces = aPolyedre->NbFaces();
994       vector<const SMDS_MeshNode *> poly_nodes;
995       vector<int> quantities (nbFaces);
996
997       // reverse each face of the polyedre
998       for (int iface = 1; iface <= nbFaces; iface++) {
999         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1000         quantities[iface - 1] = nbFaceNodes;
1001
1002         for (inode = nbFaceNodes; inode >= 1; inode--) {
1003           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1004           poly_nodes.push_back(curNode);
1005         }
1006       }
1007
1008       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1009
1010     }
1011     else {
1012       SMDS_VolumeTool vTool;
1013       if ( !vTool.Set( theElem ))
1014         return false;
1015       vTool.Inverse();
1016       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
1017       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
1018     }
1019   }
1020   default:;
1021   }
1022
1023   return false;
1024 }
1025
1026 //=======================================================================
1027 //function : getBadRate
1028 //purpose  :
1029 //=======================================================================
1030
1031 static double getBadRate (const SMDS_MeshElement*               theElem,
1032                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1033 {
1034   SMESH::Controls::TSequenceOfXYZ P;
1035   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1036     return 1e100;
1037   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1038   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1039 }
1040
1041 //=======================================================================
1042 //function : QuadToTri
1043 //purpose  : Cut quadrangles into triangles.
1044 //           theCrit is used to select a diagonal to cut
1045 //=======================================================================
1046
1047 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1048                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1049 {
1050   myLastCreatedElems.Clear();
1051   myLastCreatedNodes.Clear();
1052
1053   MESSAGE( "::QuadToTri()" );
1054
1055   if ( !theCrit.get() )
1056     return false;
1057
1058   SMESHDS_Mesh * aMesh = GetMeshDS();
1059
1060   Handle(Geom_Surface) surface;
1061   SMESH_MesherHelper   helper( *GetMesh() );
1062
1063   TIDSortedElemSet::iterator itElem;
1064   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1065     const SMDS_MeshElement* elem = *itElem;
1066     if ( !elem || elem->GetType() != SMDSAbs_Face )
1067       continue;
1068     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1069       continue;
1070
1071     // retrieve element nodes
1072     const SMDS_MeshNode* aNodes [8];
1073     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1074     int i = 0;
1075     while ( itN->more() )
1076       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1077
1078     // compare two sets of possible triangles
1079     double aBadRate1, aBadRate2; // to what extent a set is bad
1080     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1081     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1082     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1083
1084     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1085     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1086     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1087
1088     int aShapeId = FindShape( elem );
1089     const SMDS_MeshElement* newElem1 = 0;
1090     const SMDS_MeshElement* newElem2 = 0;
1091
1092     if( !elem->IsQuadratic() ) {
1093
1094       // split liner quadrangle
1095       if ( aBadRate1 <= aBadRate2 ) {
1096         // tr1 + tr2 is better
1097         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1098         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1099       }
1100       else {
1101         // tr3 + tr4 is better
1102         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1103         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1104       }
1105     }
1106     else {
1107
1108       // split quadratic quadrangle
1109
1110       // get surface elem is on
1111       if ( aShapeId != helper.GetSubShapeID() ) {
1112         surface.Nullify();
1113         TopoDS_Shape shape;
1114         if ( aShapeId > 0 )
1115           shape = aMesh->IndexToShape( aShapeId );
1116         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1117           TopoDS_Face face = TopoDS::Face( shape );
1118           surface = BRep_Tool::Surface( face );
1119           if ( !surface.IsNull() )
1120             helper.SetSubShape( shape );
1121         }
1122       }
1123       // get elem nodes
1124       const SMDS_MeshNode* aNodes [8];
1125       const SMDS_MeshNode* inFaceNode = 0;
1126       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1127       int i = 0;
1128       while ( itN->more() ) {
1129         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1130         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1131              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1132         {
1133           inFaceNode = aNodes[ i-1 ];
1134         }
1135       }
1136       // find middle point for (0,1,2,3)
1137       // and create a node in this point;
1138       gp_XYZ p( 0,0,0 );
1139       if ( surface.IsNull() ) {
1140         for(i=0; i<4; i++)
1141           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1142         p /= 4;
1143       }
1144       else {
1145         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1146         gp_XY uv( 0,0 );
1147         for(i=0; i<4; i++)
1148           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1149         uv /= 4.;
1150         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1151       }
1152       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1153       myLastCreatedNodes.Append(newN);
1154
1155       // create a new element
1156       if ( aBadRate1 <= aBadRate2 ) {
1157         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1158                                   aNodes[6], aNodes[7], newN );
1159         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1160                                   newN,      aNodes[4], aNodes[5] );
1161       }
1162       else {
1163         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1164                                   aNodes[7], aNodes[4], newN );
1165         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1166                                   newN,      aNodes[5], aNodes[6] );
1167       }
1168     } // quadratic case
1169
1170     // care of a new element
1171
1172     myLastCreatedElems.Append(newElem1);
1173     myLastCreatedElems.Append(newElem2);
1174     AddToSameGroups( newElem1, elem, aMesh );
1175     AddToSameGroups( newElem2, elem, aMesh );
1176
1177     // put a new triangle on the same shape
1178     if ( aShapeId )
1179       {
1180         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1181         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1182       }
1183     aMesh->RemoveElement( elem );
1184   }
1185   return true;
1186 }
1187
1188 //=======================================================================
1189 //function : BestSplit
1190 //purpose  : Find better diagonal for cutting.
1191 //=======================================================================
1192
1193 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1194                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1195 {
1196   myLastCreatedElems.Clear();
1197   myLastCreatedNodes.Clear();
1198
1199   if (!theCrit.get())
1200     return -1;
1201
1202   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1203     return -1;
1204
1205   if( theQuad->NbNodes()==4 ||
1206       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1207
1208     // retrieve element nodes
1209     const SMDS_MeshNode* aNodes [4];
1210     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1211     int i = 0;
1212     //while (itN->more())
1213     while (i<4) {
1214       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1215     }
1216     // compare two sets of possible triangles
1217     double aBadRate1, aBadRate2; // to what extent a set is bad
1218     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1219     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1220     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1221
1222     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1223     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1224     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1225
1226     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1227       return 1; // diagonal 1-3
1228
1229     return 2; // diagonal 2-4
1230   }
1231   return -1;
1232 }
1233
1234 namespace
1235 {
1236   // Methods of splitting volumes into tetra
1237
1238   const int theHexTo5_1[5*4+1] =
1239     {
1240       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1241     };
1242   const int theHexTo5_2[5*4+1] =
1243     {
1244       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1245     };
1246   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1247
1248   const int theHexTo6_1[6*4+1] =
1249     {
1250       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
1251     };
1252   const int theHexTo6_2[6*4+1] =
1253     {
1254       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
1255     };
1256   const int theHexTo6_3[6*4+1] =
1257     {
1258       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
1259     };
1260   const int theHexTo6_4[6*4+1] =
1261     {
1262       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
1263     };
1264   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1265
1266   const int thePyraTo2_1[2*4+1] =
1267     {
1268       0, 1, 2, 4,    0, 2, 3, 4,   -1
1269     };
1270   const int thePyraTo2_2[2*4+1] =
1271     {
1272       1, 2, 3, 4,    1, 3, 0, 4,   -1
1273     };
1274   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1275
1276   const int thePentaTo3_1[3*4+1] =
1277     {
1278       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1279     };
1280   const int thePentaTo3_2[3*4+1] =
1281     {
1282       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1283     };
1284   const int thePentaTo3_3[3*4+1] =
1285     {
1286       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1287     };
1288   const int thePentaTo3_4[3*4+1] =
1289     {
1290       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1291     };
1292   const int thePentaTo3_5[3*4+1] =
1293     {
1294       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1295     };
1296   const int thePentaTo3_6[3*4+1] =
1297     {
1298       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1299     };
1300   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1301                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1302
1303   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1304   {
1305     int _n1, _n2, _n3;
1306     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1307     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1308     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1309   };
1310   struct TSplitMethod
1311   {
1312     int        _nbTetra;
1313     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1314     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1315     bool       _ownConn;      //!< to delete _connectivity in destructor
1316     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1317
1318     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1319       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1320     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1321     bool hasFacet( const TTriangleFacet& facet ) const
1322     {
1323       const int* tetConn = _connectivity;
1324       for ( ; tetConn[0] >= 0; tetConn += 4 )
1325         if (( facet.contains( tetConn[0] ) +
1326               facet.contains( tetConn[1] ) +
1327               facet.contains( tetConn[2] ) +
1328               facet.contains( tetConn[3] )) == 3 )
1329           return true;
1330       return false;
1331     }
1332   };
1333
1334   //=======================================================================
1335   /*!
1336    * \brief return TSplitMethod for the given element
1337    */
1338   //=======================================================================
1339
1340   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1341   {
1342     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1343
1344     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1345     // an edge and a face barycenter; tertaherdons are based on triangles and
1346     // a volume barycenter
1347     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1348
1349     // Find out how adjacent volumes are split
1350
1351     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1352     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1353     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1354     {
1355       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1356       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1357       if ( nbNodes < 4 ) continue;
1358
1359       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1360       const int* nInd = vol.GetFaceNodesIndices( iF );
1361       if ( nbNodes == 4 )
1362       {
1363         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1364         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1365         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1366         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1367       }
1368       else
1369       {
1370         int iCom = 0; // common node of triangle faces to split into
1371         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1372         {
1373           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1374                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1375                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1376           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1377                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1378                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1379           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1380           {
1381             triaSplits.push_back( t012 );
1382             triaSplits.push_back( t023 );
1383             break;
1384           }
1385         }
1386       }
1387       if ( !triaSplits.empty() )
1388         hasAdjacentSplits = true;
1389     }
1390
1391     // Among variants of split method select one compliant with adjacent volumes
1392
1393     TSplitMethod method;
1394     if ( !vol.Element()->IsPoly() && !is24TetMode )
1395     {
1396       int nbVariants = 2, nbTet = 0;
1397       const int** connVariants = 0;
1398       switch ( vol.Element()->GetEntityType() )
1399       {
1400       case SMDSEntity_Hexa:
1401       case SMDSEntity_Quad_Hexa:
1402         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1403           connVariants = theHexTo5, nbTet = 5;
1404         else
1405           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1406         break;
1407       case SMDSEntity_Pyramid:
1408       case SMDSEntity_Quad_Pyramid:
1409         connVariants = thePyraTo2;  nbTet = 2;
1410         break;
1411       case SMDSEntity_Penta:
1412       case SMDSEntity_Quad_Penta:
1413         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1414         break;
1415       default:
1416         nbVariants = 0;
1417       }
1418       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1419       {
1420         // check method compliancy with adjacent tetras,
1421         // all found splits must be among facets of tetras described by this method
1422         method = TSplitMethod( nbTet, connVariants[variant] );
1423         if ( hasAdjacentSplits && method._nbTetra > 0 )
1424         {
1425           bool facetCreated = true;
1426           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1427           {
1428             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1429             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1430               facetCreated = method.hasFacet( *facet );
1431           }
1432           if ( !facetCreated )
1433             method = TSplitMethod(0); // incompatible method
1434         }
1435       }
1436     }
1437     if ( method._nbTetra < 1 )
1438     {
1439       // No standard method is applicable, use a generic solution:
1440       // each facet of a volume is split into triangles and
1441       // each of triangles and a volume barycenter form a tetrahedron.
1442
1443       int* connectivity = new int[ maxTetConnSize + 1 ];
1444       method._connectivity = connectivity;
1445       method._ownConn = true;
1446       method._baryNode = true;
1447
1448       int connSize = 0;
1449       int baryCenInd = vol.NbNodes();
1450       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1451       {
1452         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1453         const int*   nInd = vol.GetFaceNodesIndices( iF );
1454         // find common node of triangle facets of tetra to create
1455         int iCommon = 0; // index in linear numeration
1456         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1457         if ( !triaSplits.empty() )
1458         {
1459           // by found facets
1460           const TTriangleFacet* facet = &triaSplits.front();
1461           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1462             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1463                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1464               break;
1465         }
1466         else if ( nbNodes > 3 && !is24TetMode )
1467         {
1468           // find the best method of splitting into triangles by aspect ratio
1469           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1470           map< double, int > badness2iCommon;
1471           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1472           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1473           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1474             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1475             {
1476               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1477                                       nodes[ iQ*((iLast-1)%nbNodes)],
1478                                       nodes[ iQ*((iLast  )%nbNodes)]);
1479               double badness = getBadRate( &tria, aspectRatio );
1480               badness2iCommon.insert( make_pair( badness, iCommon ));
1481             }
1482           // use iCommon with lowest badness
1483           iCommon = badness2iCommon.begin()->second;
1484         }
1485         if ( iCommon >= nbNodes )
1486           iCommon = 0; // something wrong
1487
1488         // fill connectivity of tetrahedra based on a current face
1489         int nbTet = nbNodes - 2;
1490         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1491         {
1492           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1493           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1494           nbTet = nbNodes;
1495           for ( int i = 0; i < nbTet; ++i )
1496           {
1497             int i1 = i, i2 = (i+1) % nbNodes;
1498             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1499             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1500             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1501             connectivity[ connSize++ ] = faceBaryCenInd;
1502             connectivity[ connSize++ ] = baryCenInd;
1503           }
1504         }
1505         else
1506         {
1507           for ( int i = 0; i < nbTet; ++i )
1508           {
1509             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1510             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1511             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1512             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1513             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1514             connectivity[ connSize++ ] = baryCenInd;
1515           }
1516         }
1517         method._nbTetra += nbTet;
1518       }
1519       connectivity[ connSize++ ] = -1;
1520     }
1521     return method;
1522   }
1523   //================================================================================
1524   /*!
1525    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1526    */
1527   //================================================================================
1528
1529   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1530   {
1531     // find the tetrahedron including the three nodes of facet
1532     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1533     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1534     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1535     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1536     while ( volIt1->more() )
1537     {
1538       const SMDS_MeshElement* v = volIt1->next();
1539       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1540         continue;
1541       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1542       while ( volIt2->more() )
1543         if ( v != volIt2->next() )
1544           continue;
1545       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1546       while ( volIt3->more() )
1547         if ( v == volIt3->next() )
1548           return true;
1549     }
1550     return false;
1551   }
1552
1553   //=======================================================================
1554   /*!
1555    * \brief A key of a face of volume
1556    */
1557   //=======================================================================
1558
1559   struct TVolumeFaceKey: pair< int, pair< int, int> >
1560   {
1561     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1562     {
1563       TIDSortedNodeSet sortedNodes;
1564       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1565       int nbNodes = vol.NbFaceNodes( iF );
1566       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1567       for ( int i = 0; i < nbNodes; i += iQ )
1568         sortedNodes.insert( fNodes[i] );
1569       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1570       first = (*(n++))->GetID();
1571       second.first = (*(n++))->GetID();
1572       second.second = (*(n++))->GetID();
1573     }
1574   };
1575 } // namespace
1576
1577 //=======================================================================
1578 //function : SplitVolumesIntoTetra
1579 //purpose  : Split volumic elements into tetrahedra.
1580 //=======================================================================
1581
1582 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1583                                               const int                theMethodFlags)
1584 {
1585   // std-like iterator on coordinates of nodes of mesh element
1586   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1587   NXyzIterator xyzEnd;
1588
1589   SMDS_VolumeTool    volTool;
1590   SMESH_MesherHelper helper( *GetMesh());
1591
1592   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1593   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1594   
1595   SMESH_SequenceOfElemPtr newNodes, newElems;
1596
1597   // map face of volume to it's baricenrtic node
1598   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1599   double bc[3];
1600
1601   TIDSortedElemSet::const_iterator elem = theElems.begin();
1602   for ( ; elem != theElems.end(); ++elem )
1603   {
1604     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1605     if ( geomType <= SMDSEntity_Quad_Tetra )
1606       continue; // tetra or face or ...
1607
1608     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1609
1610     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1611     if ( splitMethod._nbTetra < 1 ) continue;
1612
1613     // find submesh to add new tetras to
1614     if ( !subMesh || !subMesh->Contains( *elem ))
1615     {
1616       int shapeID = FindShape( *elem );
1617       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1618       subMesh = GetMeshDS()->MeshElements( shapeID );
1619     }
1620     int iQ;
1621     if ( (*elem)->IsQuadratic() )
1622     {
1623       iQ = 2;
1624       // add quadratic links to the helper
1625       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1626       {
1627         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1628         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1629           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1630       }
1631       helper.SetIsQuadratic( true );
1632     }
1633     else
1634     {
1635       iQ = 1;
1636       helper.SetIsQuadratic( false );
1637     }
1638     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1639     helper.SetElementsOnShape( true );
1640     if ( splitMethod._baryNode )
1641     {
1642       // make a node at barycenter
1643       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1644       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1645       nodes.push_back( gcNode );
1646       newNodes.Append( gcNode );
1647     }
1648     if ( !splitMethod._faceBaryNode.empty() )
1649     {
1650       // make or find baricentric nodes of faces
1651       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1652       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1653       {
1654         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1655           volFace2BaryNode.insert
1656           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1657         if ( !f_n->second )
1658         {
1659           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1660           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1661         }
1662         nodes.push_back( iF_n->second = f_n->second );
1663       }
1664     }
1665
1666     // make tetras
1667     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1668     const int* tetConn = splitMethod._connectivity;
1669     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1670       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1671                                                        nodes[ tetConn[1] ],
1672                                                        nodes[ tetConn[2] ],
1673                                                        nodes[ tetConn[3] ]));
1674
1675     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1676
1677     // Split faces on sides of the split volume
1678
1679     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1680     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1681     {
1682       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1683       if ( nbNodes < 4 ) continue;
1684
1685       // find an existing face
1686       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1687                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1688       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1689       {
1690         // make triangles
1691         helper.SetElementsOnShape( false );
1692         vector< const SMDS_MeshElement* > triangles;
1693
1694         // find submesh to add new triangles in
1695         if ( !fSubMesh || !fSubMesh->Contains( face ))
1696         {
1697           int shapeID = FindShape( face );
1698           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1699         }
1700         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1701         if ( iF_n != splitMethod._faceBaryNode.end() )
1702         {
1703           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1704           {
1705             const SMDS_MeshNode* n1 = fNodes[iN];
1706             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1707             const SMDS_MeshNode *n3 = iF_n->second;
1708             if ( !volTool.IsFaceExternal( iF ))
1709               swap( n2, n3 );
1710             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1711
1712             if ( fSubMesh && n3->getshapeId() < 1 )
1713               fSubMesh->AddNode( n3 );
1714           }
1715         }
1716         else
1717         {
1718           // among possible triangles create ones discribed by split method
1719           const int* nInd = volTool.GetFaceNodesIndices( iF );
1720           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1721           int iCom = 0; // common node of triangle faces to split into
1722           list< TTriangleFacet > facets;
1723           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1724           {
1725             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1726                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1727                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1728             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1729                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1730                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1731             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1732             {
1733               facets.push_back( t012 );
1734               facets.push_back( t023 );
1735               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1736                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1737                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1738                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1739               break;
1740             }
1741           }
1742           list< TTriangleFacet >::iterator facet = facets.begin();
1743           for ( ; facet != facets.end(); ++facet )
1744           {
1745             if ( !volTool.IsFaceExternal( iF ))
1746               swap( facet->_n2, facet->_n3 );
1747             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1748                                                  volNodes[ facet->_n2 ],
1749                                                  volNodes[ facet->_n3 ]));
1750           }
1751         }
1752         for ( int i = 0; i < triangles.size(); ++i )
1753         {
1754           if ( !triangles[i] ) continue;
1755           if ( fSubMesh )
1756             fSubMesh->AddElement( triangles[i]);
1757           newElems.Append( triangles[i] );
1758         }
1759         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1760         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1761       }
1762
1763     } // loop on volume faces to split them into triangles
1764
1765     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1766
1767   } // loop on volumes to split
1768
1769   myLastCreatedNodes = newNodes;
1770   myLastCreatedElems = newElems;
1771 }
1772
1773 //=======================================================================
1774 //function : AddToSameGroups
1775 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1776 //=======================================================================
1777
1778 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1779                                         const SMDS_MeshElement* elemInGroups,
1780                                         SMESHDS_Mesh *          aMesh)
1781 {
1782   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1783   if (!groups.empty()) {
1784     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1785     for ( ; grIt != groups.end(); grIt++ ) {
1786       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1787       if ( group && group->Contains( elemInGroups ))
1788         group->SMDSGroup().Add( elemToAdd );
1789     }
1790   }
1791 }
1792
1793
1794 //=======================================================================
1795 //function : RemoveElemFromGroups
1796 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1797 //=======================================================================
1798 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1799                                              SMESHDS_Mesh *          aMesh)
1800 {
1801   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1802   if (!groups.empty())
1803   {
1804     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1805     for (; GrIt != groups.end(); GrIt++)
1806     {
1807       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1808       if (!grp || grp->IsEmpty()) continue;
1809       grp->SMDSGroup().Remove(removeelem);
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 SMDS_MeshElement* elemToAdd,
1822                                             SMESHDS_Mesh *          aMesh)
1823 {
1824   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1825   if (!groups.empty()) {
1826     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1827     for ( ; grIt != groups.end(); grIt++ ) {
1828       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1829       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1830         group->SMDSGroup().Add( elemToAdd );
1831     }
1832   }
1833 }
1834
1835 //================================================================================
1836 /*!
1837  * \brief Replace elemToRm by elemToAdd in the all groups
1838  */
1839 //================================================================================
1840
1841 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1842                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1843                                             SMESHDS_Mesh *                         aMesh)
1844 {
1845   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1846   if (!groups.empty())
1847   {
1848     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1849     for ( ; grIt != groups.end(); grIt++ ) {
1850       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1851       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1852         for ( int i = 0; i < elemToAdd.size(); ++i )
1853           group->SMDSGroup().Add( elemToAdd[ i ] );
1854     }
1855   }
1856 }
1857
1858 //=======================================================================
1859 //function : QuadToTri
1860 //purpose  : Cut quadrangles into triangles.
1861 //           theCrit is used to select a diagonal to cut
1862 //=======================================================================
1863
1864 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1865                                   const bool         the13Diag)
1866 {
1867   myLastCreatedElems.Clear();
1868   myLastCreatedNodes.Clear();
1869
1870   MESSAGE( "::QuadToTri()" );
1871
1872   SMESHDS_Mesh * aMesh = GetMeshDS();
1873
1874   Handle(Geom_Surface) surface;
1875   SMESH_MesherHelper   helper( *GetMesh() );
1876
1877   TIDSortedElemSet::iterator itElem;
1878   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1879     const SMDS_MeshElement* elem = *itElem;
1880     if ( !elem || elem->GetType() != SMDSAbs_Face )
1881       continue;
1882     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1883     if(!isquad) continue;
1884
1885     if(elem->NbNodes()==4) {
1886       // retrieve element nodes
1887       const SMDS_MeshNode* aNodes [4];
1888       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1889       int i = 0;
1890       while ( itN->more() )
1891         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1892
1893       int aShapeId = FindShape( elem );
1894       const SMDS_MeshElement* newElem1 = 0;
1895       const SMDS_MeshElement* newElem2 = 0;
1896       if ( the13Diag ) {
1897         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1898         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1899       }
1900       else {
1901         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1902         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1903       }
1904       myLastCreatedElems.Append(newElem1);
1905       myLastCreatedElems.Append(newElem2);
1906       // put a new triangle on the same shape and add to the same groups
1907       if ( aShapeId )
1908         {
1909           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1910           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1911         }
1912       AddToSameGroups( newElem1, elem, aMesh );
1913       AddToSameGroups( newElem2, elem, aMesh );
1914       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1915       aMesh->RemoveElement( elem );
1916     }
1917
1918     // Quadratic quadrangle
1919
1920     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1921
1922       // get surface elem is on
1923       int aShapeId = FindShape( elem );
1924       if ( aShapeId != helper.GetSubShapeID() ) {
1925         surface.Nullify();
1926         TopoDS_Shape shape;
1927         if ( aShapeId > 0 )
1928           shape = aMesh->IndexToShape( aShapeId );
1929         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1930           TopoDS_Face face = TopoDS::Face( shape );
1931           surface = BRep_Tool::Surface( face );
1932           if ( !surface.IsNull() )
1933             helper.SetSubShape( shape );
1934         }
1935       }
1936
1937       const SMDS_MeshNode* aNodes [8];
1938       const SMDS_MeshNode* inFaceNode = 0;
1939       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1940       int i = 0;
1941       while ( itN->more() ) {
1942         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1943         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1944              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1945         {
1946           inFaceNode = aNodes[ i-1 ];
1947         }
1948       }
1949
1950       // find middle point for (0,1,2,3)
1951       // and create a node in this point;
1952       gp_XYZ p( 0,0,0 );
1953       if ( surface.IsNull() ) {
1954         for(i=0; i<4; i++)
1955           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1956         p /= 4;
1957       }
1958       else {
1959         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1960         gp_XY uv( 0,0 );
1961         for(i=0; i<4; i++)
1962           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1963         uv /= 4.;
1964         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1965       }
1966       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1967       myLastCreatedNodes.Append(newN);
1968
1969       // create a new element
1970       const SMDS_MeshElement* newElem1 = 0;
1971       const SMDS_MeshElement* newElem2 = 0;
1972       if ( the13Diag ) {
1973         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1974                                   aNodes[6], aNodes[7], newN );
1975         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1976                                   newN,      aNodes[4], aNodes[5] );
1977       }
1978       else {
1979         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1980                                   aNodes[7], aNodes[4], newN );
1981         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1982                                   newN,      aNodes[5], aNodes[6] );
1983       }
1984       myLastCreatedElems.Append(newElem1);
1985       myLastCreatedElems.Append(newElem2);
1986       // put a new triangle on the same shape and add to the same groups
1987       if ( aShapeId )
1988         {
1989           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1990           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1991         }
1992       AddToSameGroups( newElem1, elem, aMesh );
1993       AddToSameGroups( newElem2, elem, aMesh );
1994       aMesh->RemoveElement( elem );
1995     }
1996   }
1997
1998   return true;
1999 }
2000
2001 //=======================================================================
2002 //function : getAngle
2003 //purpose  :
2004 //=======================================================================
2005
2006 double getAngle(const SMDS_MeshElement * tr1,
2007                 const SMDS_MeshElement * tr2,
2008                 const SMDS_MeshNode *    n1,
2009                 const SMDS_MeshNode *    n2)
2010 {
2011   double angle = 2*PI; // bad angle
2012
2013   // get normals
2014   SMESH::Controls::TSequenceOfXYZ P1, P2;
2015   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2016        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2017     return angle;
2018   gp_Vec N1,N2;
2019   if(!tr1->IsQuadratic())
2020     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2021   else
2022     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2023   if ( N1.SquareMagnitude() <= gp::Resolution() )
2024     return angle;
2025   if(!tr2->IsQuadratic())
2026     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2027   else
2028     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2029   if ( N2.SquareMagnitude() <= gp::Resolution() )
2030     return angle;
2031
2032   // find the first diagonal node n1 in the triangles:
2033   // take in account a diagonal link orientation
2034   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2035   for ( int t = 0; t < 2; t++ ) {
2036     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2037     int i = 0, iDiag = -1;
2038     while ( it->more()) {
2039       const SMDS_MeshElement *n = it->next();
2040       if ( n == n1 || n == n2 ) {
2041         if ( iDiag < 0)
2042           iDiag = i;
2043         else {
2044           if ( i - iDiag == 1 )
2045             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2046           else
2047             nFirst[ t ] = n;
2048           break;
2049         }
2050       }
2051       i++;
2052     }
2053   }
2054   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2055     N2.Reverse();
2056
2057   angle = N1.Angle( N2 );
2058   //SCRUTE( angle );
2059   return angle;
2060 }
2061
2062 // =================================================
2063 // class generating a unique ID for a pair of nodes
2064 // and able to return nodes by that ID
2065 // =================================================
2066 class LinkID_Gen {
2067 public:
2068
2069   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2070     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2071   {}
2072
2073   long GetLinkID (const SMDS_MeshNode * n1,
2074                   const SMDS_MeshNode * n2) const
2075   {
2076     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2077   }
2078
2079   bool GetNodes (const long             theLinkID,
2080                  const SMDS_MeshNode* & theNode1,
2081                  const SMDS_MeshNode* & theNode2) const
2082   {
2083     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2084     if ( !theNode1 ) return false;
2085     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2086     if ( !theNode2 ) return false;
2087     return true;
2088   }
2089
2090 private:
2091   LinkID_Gen();
2092   const SMESHDS_Mesh* myMesh;
2093   long                myMaxID;
2094 };
2095
2096
2097 //=======================================================================
2098 //function : TriToQuad
2099 //purpose  : Fuse neighbour triangles into quadrangles.
2100 //           theCrit is used to select a neighbour to fuse with.
2101 //           theMaxAngle is a max angle between element normals at which
2102 //           fusion is still performed.
2103 //=======================================================================
2104
2105 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2106                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2107                                   const double                         theMaxAngle)
2108 {
2109   myLastCreatedElems.Clear();
2110   myLastCreatedNodes.Clear();
2111
2112   MESSAGE( "::TriToQuad()" );
2113
2114   if ( !theCrit.get() )
2115     return false;
2116
2117   SMESHDS_Mesh * aMesh = GetMeshDS();
2118
2119   // Prepare data for algo: build
2120   // 1. map of elements with their linkIDs
2121   // 2. map of linkIDs with their elements
2122
2123   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2124   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2125   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2126   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2127
2128   TIDSortedElemSet::iterator itElem;
2129   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2130     const SMDS_MeshElement* elem = *itElem;
2131     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2132     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2133     if(!IsTria) continue;
2134
2135     // retrieve element nodes
2136     const SMDS_MeshNode* aNodes [4];
2137     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2138     int i = 0;
2139     while ( i<3 )
2140       aNodes[ i++ ] = cast2Node( itN->next() );
2141     aNodes[ 3 ] = aNodes[ 0 ];
2142
2143     // fill maps
2144     for ( i = 0; i < 3; i++ ) {
2145       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2146       // check if elements sharing a link can be fused
2147       itLE = mapLi_listEl.find( link );
2148       if ( itLE != mapLi_listEl.end() ) {
2149         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2150           continue;
2151         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2152         //if ( FindShape( elem ) != FindShape( elem2 ))
2153         //  continue; // do not fuse triangles laying on different shapes
2154         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2155           continue; // avoid making badly shaped quads
2156         (*itLE).second.push_back( elem );
2157       }
2158       else {
2159         mapLi_listEl[ link ].push_back( elem );
2160       }
2161       mapEl_setLi [ elem ].insert( link );
2162     }
2163   }
2164   // Clean the maps from the links shared by a sole element, ie
2165   // links to which only one element is bound in mapLi_listEl
2166
2167   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2168     int nbElems = (*itLE).second.size();
2169     if ( nbElems < 2  ) {
2170       const SMDS_MeshElement* elem = (*itLE).second.front();
2171       SMESH_TLink link = (*itLE).first;
2172       mapEl_setLi[ elem ].erase( link );
2173       if ( mapEl_setLi[ elem ].empty() )
2174         mapEl_setLi.erase( elem );
2175     }
2176   }
2177
2178   // Algo: fuse triangles into quadrangles
2179
2180   while ( ! mapEl_setLi.empty() ) {
2181     // Look for the start element:
2182     // the element having the least nb of shared links
2183     const SMDS_MeshElement* startElem = 0;
2184     int minNbLinks = 4;
2185     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2186       int nbLinks = (*itEL).second.size();
2187       if ( nbLinks < minNbLinks ) {
2188         startElem = (*itEL).first;
2189         minNbLinks = nbLinks;
2190         if ( minNbLinks == 1 )
2191           break;
2192       }
2193     }
2194
2195     // search elements to fuse starting from startElem or links of elements
2196     // fused earlyer - startLinks
2197     list< SMESH_TLink > startLinks;
2198     while ( startElem || !startLinks.empty() ) {
2199       while ( !startElem && !startLinks.empty() ) {
2200         // Get an element to start, by a link
2201         SMESH_TLink linkId = startLinks.front();
2202         startLinks.pop_front();
2203         itLE = mapLi_listEl.find( linkId );
2204         if ( itLE != mapLi_listEl.end() ) {
2205           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2206           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2207           for ( ; itE != listElem.end() ; itE++ )
2208             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2209               startElem = (*itE);
2210           mapLi_listEl.erase( itLE );
2211         }
2212       }
2213
2214       if ( startElem ) {
2215         // Get candidates to be fused
2216         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2217         const SMESH_TLink *link12, *link13;
2218         startElem = 0;
2219         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2220         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2221         ASSERT( !setLi.empty() );
2222         set< SMESH_TLink >::iterator itLi;
2223         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2224         {
2225           const SMESH_TLink & link = (*itLi);
2226           itLE = mapLi_listEl.find( link );
2227           if ( itLE == mapLi_listEl.end() )
2228             continue;
2229
2230           const SMDS_MeshElement* elem = (*itLE).second.front();
2231           if ( elem == tr1 )
2232             elem = (*itLE).second.back();
2233           mapLi_listEl.erase( itLE );
2234           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2235             continue;
2236           if ( tr2 ) {
2237             tr3 = elem;
2238             link13 = &link;
2239           }
2240           else {
2241             tr2 = elem;
2242             link12 = &link;
2243           }
2244
2245           // add other links of elem to list of links to re-start from
2246           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2247           set< SMESH_TLink >::iterator it;
2248           for ( it = links.begin(); it != links.end(); it++ ) {
2249             const SMESH_TLink& link2 = (*it);
2250             if ( link2 != link )
2251               startLinks.push_back( link2 );
2252           }
2253         }
2254
2255         // Get nodes of possible quadrangles
2256         const SMDS_MeshNode *n12 [4], *n13 [4];
2257         bool Ok12 = false, Ok13 = false;
2258         const SMDS_MeshNode *linkNode1, *linkNode2;
2259         if(tr2) {
2260           linkNode1 = link12->first;
2261           linkNode2 = link12->second;
2262           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2263             Ok12 = true;
2264         }
2265         if(tr3) {
2266           linkNode1 = link13->first;
2267           linkNode2 = link13->second;
2268           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2269             Ok13 = true;
2270         }
2271
2272         // Choose a pair to fuse
2273         if ( Ok12 && Ok13 ) {
2274           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2275           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2276           double aBadRate12 = getBadRate( &quad12, theCrit );
2277           double aBadRate13 = getBadRate( &quad13, theCrit );
2278           if (  aBadRate13 < aBadRate12 )
2279             Ok12 = false;
2280           else
2281             Ok13 = false;
2282         }
2283
2284         // Make quadrangles
2285         // and remove fused elems and removed links from the maps
2286         mapEl_setLi.erase( tr1 );
2287         if ( Ok12 ) {
2288           mapEl_setLi.erase( tr2 );
2289           mapLi_listEl.erase( *link12 );
2290           if(tr1->NbNodes()==3) {
2291             const SMDS_MeshElement* newElem = 0;
2292             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2293             myLastCreatedElems.Append(newElem);
2294             AddToSameGroups( newElem, tr1, aMesh );
2295             int aShapeId = tr1->getshapeId();
2296             if ( aShapeId )
2297               {
2298                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2299               }
2300             aMesh->RemoveElement( tr1 );
2301             aMesh->RemoveElement( tr2 );
2302           }
2303           else {
2304             const SMDS_MeshNode* N1 [6];
2305             const SMDS_MeshNode* N2 [6];
2306             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2307             // now we receive following N1 and N2 (using numeration as above image)
2308             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2309             // i.e. first nodes from both arrays determ new diagonal
2310             const SMDS_MeshNode* aNodes[8];
2311             aNodes[0] = N1[0];
2312             aNodes[1] = N1[1];
2313             aNodes[2] = N2[0];
2314             aNodes[3] = N2[1];
2315             aNodes[4] = N1[3];
2316             aNodes[5] = N2[5];
2317             aNodes[6] = N2[3];
2318             aNodes[7] = N1[5];
2319             const SMDS_MeshElement* newElem = 0;
2320             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2321                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2322             myLastCreatedElems.Append(newElem);
2323             AddToSameGroups( newElem, tr1, aMesh );
2324             int aShapeId = tr1->getshapeId();
2325             if ( aShapeId )
2326               {
2327                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2328               }
2329             aMesh->RemoveElement( tr1 );
2330             aMesh->RemoveElement( tr2 );
2331             // remove middle node (9)
2332             GetMeshDS()->RemoveNode( N1[4] );
2333           }
2334         }
2335         else if ( Ok13 ) {
2336           mapEl_setLi.erase( tr3 );
2337           mapLi_listEl.erase( *link13 );
2338           if(tr1->NbNodes()==3) {
2339             const SMDS_MeshElement* newElem = 0;
2340             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2341             myLastCreatedElems.Append(newElem);
2342             AddToSameGroups( newElem, tr1, aMesh );
2343             int aShapeId = tr1->getshapeId();
2344             if ( aShapeId )
2345               {
2346                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2347               }
2348             aMesh->RemoveElement( tr1 );
2349             aMesh->RemoveElement( tr3 );
2350           }
2351           else {
2352             const SMDS_MeshNode* N1 [6];
2353             const SMDS_MeshNode* N2 [6];
2354             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2355             // now we receive following N1 and N2 (using numeration as above image)
2356             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2357             // i.e. first nodes from both arrays determ new diagonal
2358             const SMDS_MeshNode* aNodes[8];
2359             aNodes[0] = N1[0];
2360             aNodes[1] = N1[1];
2361             aNodes[2] = N2[0];
2362             aNodes[3] = N2[1];
2363             aNodes[4] = N1[3];
2364             aNodes[5] = N2[5];
2365             aNodes[6] = N2[3];
2366             aNodes[7] = N1[5];
2367             const SMDS_MeshElement* newElem = 0;
2368             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2369                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2370             myLastCreatedElems.Append(newElem);
2371             AddToSameGroups( newElem, tr1, aMesh );
2372             int aShapeId = tr1->getshapeId();
2373             if ( aShapeId )
2374               {
2375                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2376               }
2377             aMesh->RemoveElement( tr1 );
2378             aMesh->RemoveElement( tr3 );
2379             // remove middle node (9)
2380             GetMeshDS()->RemoveNode( N1[4] );
2381           }
2382         }
2383
2384         // Next element to fuse: the rejected one
2385         if ( tr3 )
2386           startElem = Ok12 ? tr3 : tr2;
2387
2388       } // if ( startElem )
2389     } // while ( startElem || !startLinks.empty() )
2390   } // while ( ! mapEl_setLi.empty() )
2391
2392   return true;
2393 }
2394
2395
2396 /*#define DUMPSO(txt) \
2397 //  cout << txt << endl;
2398 //=============================================================================
2399 //
2400 //
2401 //
2402 //=============================================================================
2403 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2404 {
2405 if ( i1 == i2 )
2406 return;
2407 int tmp = idNodes[ i1 ];
2408 idNodes[ i1 ] = idNodes[ i2 ];
2409 idNodes[ i2 ] = tmp;
2410 gp_Pnt Ptmp = P[ i1 ];
2411 P[ i1 ] = P[ i2 ];
2412 P[ i2 ] = Ptmp;
2413 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2414 }
2415
2416 //=======================================================================
2417 //function : SortQuadNodes
2418 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2419 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2420 //           1 or 2 else 0.
2421 //=======================================================================
2422
2423 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2424 int               idNodes[] )
2425 {
2426   gp_Pnt P[4];
2427   int i;
2428   for ( i = 0; i < 4; i++ ) {
2429     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2430     if ( !n ) return 0;
2431     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2432   }
2433
2434   gp_Vec V1(P[0], P[1]);
2435   gp_Vec V2(P[0], P[2]);
2436   gp_Vec V3(P[0], P[3]);
2437
2438   gp_Vec Cross1 = V1 ^ V2;
2439   gp_Vec Cross2 = V2 ^ V3;
2440
2441   i = 0;
2442   if (Cross1.Dot(Cross2) < 0)
2443   {
2444     Cross1 = V2 ^ V1;
2445     Cross2 = V1 ^ V3;
2446
2447     if (Cross1.Dot(Cross2) < 0)
2448       i = 2;
2449     else
2450       i = 1;
2451     swap ( i, i + 1, idNodes, P );
2452
2453     //     for ( int ii = 0; ii < 4; ii++ ) {
2454     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2455     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2456     //     }
2457   }
2458   return i;
2459 }
2460
2461 //=======================================================================
2462 //function : SortHexaNodes
2463 //purpose  : Set 8 nodes of a hexahedron in a good order.
2464 //           Return success status
2465 //=======================================================================
2466
2467 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2468                                       int               idNodes[] )
2469 {
2470   gp_Pnt P[8];
2471   int i;
2472   DUMPSO( "INPUT: ========================================");
2473   for ( i = 0; i < 8; i++ ) {
2474     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2475     if ( !n ) return false;
2476     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2477     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2478   }
2479   DUMPSO( "========================================");
2480
2481
2482   set<int> faceNodes;  // ids of bottom face nodes, to be found
2483   set<int> checkedId1; // ids of tried 2-nd nodes
2484   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2485   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2486   int iMin, iLoop1 = 0;
2487
2488   // Loop to try the 2-nd nodes
2489
2490   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2491   {
2492     // Find not checked 2-nd node
2493     for ( i = 1; i < 8; i++ )
2494       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2495         int id1 = idNodes[i];
2496         swap ( 1, i, idNodes, P );
2497         checkedId1.insert ( id1 );
2498         break;
2499       }
2500
2501     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2502     // ie that all but meybe one (id3 which is on the same face) nodes
2503     // lay on the same side from the triangle plane.
2504
2505     bool manyInPlane = false; // more than 4 nodes lay in plane
2506     int iLoop2 = 0;
2507     while ( ++iLoop2 < 6 ) {
2508
2509       // get 1-2-3 plane coeffs
2510       Standard_Real A, B, C, D;
2511       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2512       if ( N.SquareMagnitude() > gp::Resolution() )
2513       {
2514         gp_Pln pln ( P[0], N );
2515         pln.Coefficients( A, B, C, D );
2516
2517         // find the node (iMin) closest to pln
2518         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2519         set<int> idInPln;
2520         for ( i = 3; i < 8; i++ ) {
2521           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2522           if ( fabs( dist[i] ) < minDist ) {
2523             minDist = fabs( dist[i] );
2524             iMin = i;
2525           }
2526           if ( fabs( dist[i] ) <= tol )
2527             idInPln.insert( idNodes[i] );
2528         }
2529
2530         // there should not be more than 4 nodes in bottom plane
2531         if ( idInPln.size() > 1 )
2532         {
2533           DUMPSO( "### idInPln.size() = " << idInPln.size());
2534           // idInPlane does not contain the first 3 nodes
2535           if ( manyInPlane || idInPln.size() == 5)
2536             return false; // all nodes in one plane
2537           manyInPlane = true;
2538
2539           // set the 1-st node to be not in plane
2540           for ( i = 3; i < 8; i++ ) {
2541             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2542               DUMPSO( "### Reset 0-th node");
2543               swap( 0, i, idNodes, P );
2544               break;
2545             }
2546           }
2547
2548           // reset to re-check second nodes
2549           leastDist = DBL_MAX;
2550           faceNodes.clear();
2551           checkedId1.clear();
2552           iLoop1 = 0;
2553           break; // from iLoop2;
2554         }
2555
2556         // check that the other 4 nodes are on the same side
2557         bool sameSide = true;
2558         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2559         for ( i = 3; sameSide && i < 8; i++ ) {
2560           if ( i != iMin )
2561             sameSide = ( isNeg == dist[i] <= 0.);
2562         }
2563
2564         // keep best solution
2565         if ( sameSide && minDist < leastDist ) {
2566           leastDist = minDist;
2567           faceNodes.clear();
2568           faceNodes.insert( idNodes[ 1 ] );
2569           faceNodes.insert( idNodes[ 2 ] );
2570           faceNodes.insert( idNodes[ iMin ] );
2571           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2572                   << " leastDist = " << leastDist);
2573           if ( leastDist <= DBL_MIN )
2574             break;
2575         }
2576       }
2577
2578       // set next 3-d node to check
2579       int iNext = 2 + iLoop2;
2580       if ( iNext < 8 ) {
2581         DUMPSO( "Try 2-nd");
2582         swap ( 2, iNext, idNodes, P );
2583       }
2584     } // while ( iLoop2 < 6 )
2585   } // iLoop1
2586
2587   if ( faceNodes.empty() ) return false;
2588
2589   // Put the faceNodes in proper places
2590   for ( i = 4; i < 8; i++ ) {
2591     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2592       // find a place to put
2593       int iTo = 1;
2594       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2595         iTo++;
2596       DUMPSO( "Set faceNodes");
2597       swap ( iTo, i, idNodes, P );
2598     }
2599   }
2600
2601
2602   // Set nodes of the found bottom face in good order
2603   DUMPSO( " Found bottom face: ");
2604   i = SortQuadNodes( theMesh, idNodes );
2605   if ( i ) {
2606     gp_Pnt Ptmp = P[ i ];
2607     P[ i ] = P[ i+1 ];
2608     P[ i+1 ] = Ptmp;
2609   }
2610   //   else
2611   //     for ( int ii = 0; ii < 4; ii++ ) {
2612   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2613   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2614   //    }
2615
2616   // Gravity center of the top and bottom faces
2617   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2618   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2619
2620   // Get direction from the bottom to the top face
2621   gp_Vec upDir ( aGCb, aGCt );
2622   Standard_Real upDirSize = upDir.Magnitude();
2623   if ( upDirSize <= gp::Resolution() ) return false;
2624   upDir / upDirSize;
2625
2626   // Assure that the bottom face normal points up
2627   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2628   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2629   if ( Nb.Dot( upDir ) < 0 ) {
2630     DUMPSO( "Reverse bottom face");
2631     swap( 1, 3, idNodes, P );
2632   }
2633
2634   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2635   Standard_Real minDist = DBL_MAX;
2636   for ( i = 4; i < 8; i++ ) {
2637     // projection of P[i] to the plane defined by P[0] and upDir
2638     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2639     Standard_Real sqDist = P[0].SquareDistance( Pp );
2640     if ( sqDist < minDist ) {
2641       minDist = sqDist;
2642       iMin = i;
2643     }
2644   }
2645   DUMPSO( "Set 4-th");
2646   swap ( 4, iMin, idNodes, P );
2647
2648   // Set nodes of the top face in good order
2649   DUMPSO( "Sort top face");
2650   i = SortQuadNodes( theMesh, &idNodes[4] );
2651   if ( i ) {
2652     i += 4;
2653     gp_Pnt Ptmp = P[ i ];
2654     P[ i ] = P[ i+1 ];
2655     P[ i+1 ] = Ptmp;
2656   }
2657
2658   // Assure that direction of the top face normal is from the bottom face
2659   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2660   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2661   if ( Nt.Dot( upDir ) < 0 ) {
2662     DUMPSO( "Reverse top face");
2663     swap( 5, 7, idNodes, P );
2664   }
2665
2666   //   DUMPSO( "OUTPUT: ========================================");
2667   //   for ( i = 0; i < 8; i++ ) {
2668   //     float *p = ugrid->GetPoint(idNodes[i]);
2669   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2670   //   }
2671
2672   return true;
2673 }*/
2674
2675 //================================================================================
2676 /*!
2677  * \brief Return nodes linked to the given one
2678  * \param theNode - the node
2679  * \param linkedNodes - the found nodes
2680  * \param type - the type of elements to check
2681  *
2682  * Medium nodes are ignored
2683  */
2684 //================================================================================
2685
2686 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2687                                        TIDSortedElemSet &   linkedNodes,
2688                                        SMDSAbs_ElementType  type )
2689 {
2690   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2691   while ( elemIt->more() )
2692   {
2693     const SMDS_MeshElement* elem = elemIt->next();
2694     if(elem->GetType() == SMDSAbs_0DElement)
2695       continue;
2696     
2697     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2698     if ( elem->GetType() == SMDSAbs_Volume )
2699     {
2700       SMDS_VolumeTool vol( elem );
2701       while ( nodeIt->more() ) {
2702         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2703         if ( theNode != n && vol.IsLinked( theNode, n ))
2704           linkedNodes.insert( n );
2705       }
2706     }
2707     else
2708     {
2709       for ( int i = 0; nodeIt->more(); ++i ) {
2710         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2711         if ( n == theNode ) {
2712           int iBefore = i - 1;
2713           int iAfter  = i + 1;
2714           if ( elem->IsQuadratic() ) {
2715             int nb = elem->NbNodes() / 2;
2716             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2717             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2718           }
2719           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2720           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2721         }
2722       }
2723     }
2724   }
2725 }
2726
2727 //=======================================================================
2728 //function : laplacianSmooth
2729 //purpose  : pulls theNode toward the center of surrounding nodes directly
2730 //           connected to that node along an element edge
2731 //=======================================================================
2732
2733 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2734                      const Handle(Geom_Surface)&          theSurface,
2735                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2736 {
2737   // find surrounding nodes
2738
2739   TIDSortedElemSet nodeSet;
2740   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2741
2742   // compute new coodrs
2743
2744   double coord[] = { 0., 0., 0. };
2745   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2746   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2747     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2748     if ( theSurface.IsNull() ) { // smooth in 3D
2749       coord[0] += node->X();
2750       coord[1] += node->Y();
2751       coord[2] += node->Z();
2752     }
2753     else { // smooth in 2D
2754       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2755       gp_XY* uv = theUVMap[ node ];
2756       coord[0] += uv->X();
2757       coord[1] += uv->Y();
2758     }
2759   }
2760   int nbNodes = nodeSet.size();
2761   if ( !nbNodes )
2762     return;
2763   coord[0] /= nbNodes;
2764   coord[1] /= nbNodes;
2765
2766   if ( !theSurface.IsNull() ) {
2767     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2768     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2769     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2770     coord[0] = p3d.X();
2771     coord[1] = p3d.Y();
2772     coord[2] = p3d.Z();
2773   }
2774   else
2775     coord[2] /= nbNodes;
2776
2777   // move node
2778
2779   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2780 }
2781
2782 //=======================================================================
2783 //function : centroidalSmooth
2784 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2785 //           surrounding elements
2786 //=======================================================================
2787
2788 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2789                       const Handle(Geom_Surface)&          theSurface,
2790                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2791 {
2792   gp_XYZ aNewXYZ(0.,0.,0.);
2793   SMESH::Controls::Area anAreaFunc;
2794   double totalArea = 0.;
2795   int nbElems = 0;
2796
2797   // compute new XYZ
2798
2799   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2800   while ( elemIt->more() )
2801   {
2802     const SMDS_MeshElement* elem = elemIt->next();
2803     nbElems++;
2804
2805     gp_XYZ elemCenter(0.,0.,0.);
2806     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2807     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2808     int nn = elem->NbNodes();
2809     if(elem->IsQuadratic()) nn = nn/2;
2810     int i=0;
2811     //while ( itN->more() ) {
2812     while ( i<nn ) {
2813       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2814       i++;
2815       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2816       aNodePoints.push_back( aP );
2817       if ( !theSurface.IsNull() ) { // smooth in 2D
2818         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2819         gp_XY* uv = theUVMap[ aNode ];
2820         aP.SetCoord( uv->X(), uv->Y(), 0. );
2821       }
2822       elemCenter += aP;
2823     }
2824     double elemArea = anAreaFunc.GetValue( aNodePoints );
2825     totalArea += elemArea;
2826     elemCenter /= nn;
2827     aNewXYZ += elemCenter * elemArea;
2828   }
2829   aNewXYZ /= totalArea;
2830   if ( !theSurface.IsNull() ) {
2831     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2832     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2833   }
2834
2835   // move node
2836
2837   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2838 }
2839
2840 //=======================================================================
2841 //function : getClosestUV
2842 //purpose  : return UV of closest projection
2843 //=======================================================================
2844
2845 static bool getClosestUV (Extrema_GenExtPS& projector,
2846                           const gp_Pnt&     point,
2847                           gp_XY &           result)
2848 {
2849   projector.Perform( point );
2850   if ( projector.IsDone() ) {
2851     double u, v, minVal = DBL_MAX;
2852     for ( int i = projector.NbExt(); i > 0; i-- )
2853 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
2854       if ( projector.SquareDistance( i ) < minVal ) {
2855         minVal = projector.SquareDistance( i );
2856 #else
2857       if ( projector.Value( i ) < minVal ) {
2858         minVal = projector.Value( i );
2859 #endif
2860         projector.Point( i ).Parameter( u, v );
2861       }
2862     result.SetCoord( u, v );
2863     return true;
2864   }
2865   return false;
2866 }
2867
2868 //=======================================================================
2869 //function : Smooth
2870 //purpose  : Smooth theElements during theNbIterations or until a worst
2871 //           element has aspect ratio <= theTgtAspectRatio.
2872 //           Aspect Ratio varies in range [1.0, inf].
2873 //           If theElements is empty, the whole mesh is smoothed.
2874 //           theFixedNodes contains additionally fixed nodes. Nodes built
2875 //           on edges and boundary nodes are always fixed.
2876 //=======================================================================
2877
2878 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2879                                set<const SMDS_MeshNode*> & theFixedNodes,
2880                                const SmoothMethod          theSmoothMethod,
2881                                const int                   theNbIterations,
2882                                double                      theTgtAspectRatio,
2883                                const bool                  the2D)
2884 {
2885   myLastCreatedElems.Clear();
2886   myLastCreatedNodes.Clear();
2887
2888   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2889
2890   if ( theTgtAspectRatio < 1.0 )
2891     theTgtAspectRatio = 1.0;
2892
2893   const double disttol = 1.e-16;
2894
2895   SMESH::Controls::AspectRatio aQualityFunc;
2896
2897   SMESHDS_Mesh* aMesh = GetMeshDS();
2898
2899   if ( theElems.empty() ) {
2900     // add all faces to theElems
2901     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2902     while ( fIt->more() ) {
2903       const SMDS_MeshElement* face = fIt->next();
2904       theElems.insert( face );
2905     }
2906   }
2907   // get all face ids theElems are on
2908   set< int > faceIdSet;
2909   TIDSortedElemSet::iterator itElem;
2910   if ( the2D )
2911     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2912       int fId = FindShape( *itElem );
2913       // check that corresponding submesh exists and a shape is face
2914       if (fId &&
2915           faceIdSet.find( fId ) == faceIdSet.end() &&
2916           aMesh->MeshElements( fId )) {
2917         TopoDS_Shape F = aMesh->IndexToShape( fId );
2918         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2919           faceIdSet.insert( fId );
2920       }
2921     }
2922   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2923
2924   // ===============================================
2925   // smooth elements on each TopoDS_Face separately
2926   // ===============================================
2927
2928   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2929   for ( ; fId != faceIdSet.rend(); ++fId ) {
2930     // get face surface and submesh
2931     Handle(Geom_Surface) surface;
2932     SMESHDS_SubMesh* faceSubMesh = 0;
2933     TopoDS_Face face;
2934     double fToler2 = 0, f,l;
2935     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2936     bool isUPeriodic = false, isVPeriodic = false;
2937     if ( *fId ) {
2938       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2939       surface = BRep_Tool::Surface( face );
2940       faceSubMesh = aMesh->MeshElements( *fId );
2941       fToler2 = BRep_Tool::Tolerance( face );
2942       fToler2 *= fToler2 * 10.;
2943       isUPeriodic = surface->IsUPeriodic();
2944       if ( isUPeriodic )
2945         surface->UPeriod();
2946       isVPeriodic = surface->IsVPeriodic();
2947       if ( isVPeriodic )
2948         surface->VPeriod();
2949       surface->Bounds( u1, u2, v1, v2 );
2950     }
2951     // ---------------------------------------------------------
2952     // for elements on a face, find movable and fixed nodes and
2953     // compute UV for them
2954     // ---------------------------------------------------------
2955     bool checkBoundaryNodes = false;
2956     bool isQuadratic = false;
2957     set<const SMDS_MeshNode*> setMovableNodes;
2958     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2959     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2960     list< const SMDS_MeshElement* > elemsOnFace;
2961
2962     Extrema_GenExtPS projector;
2963     GeomAdaptor_Surface surfAdaptor;
2964     if ( !surface.IsNull() ) {
2965       surfAdaptor.Load( surface );
2966       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2967     }
2968     int nbElemOnFace = 0;
2969     itElem = theElems.begin();
2970     // loop on not yet smoothed elements: look for elems on a face
2971     while ( itElem != theElems.end() ) {
2972       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2973         break; // all elements found
2974
2975       const SMDS_MeshElement* elem = *itElem;
2976       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2977            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2978         ++itElem;
2979         continue;
2980       }
2981       elemsOnFace.push_back( elem );
2982       theElems.erase( itElem++ );
2983       nbElemOnFace++;
2984
2985       if ( !isQuadratic )
2986         isQuadratic = elem->IsQuadratic();
2987
2988       // get movable nodes of elem
2989       const SMDS_MeshNode* node;
2990       SMDS_TypeOfPosition posType;
2991       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2992       int nn = 0, nbn =  elem->NbNodes();
2993       if(elem->IsQuadratic())
2994         nbn = nbn/2;
2995       while ( nn++ < nbn ) {
2996         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2997         const SMDS_PositionPtr& pos = node->GetPosition();
2998         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2999         if (posType != SMDS_TOP_EDGE &&
3000             posType != SMDS_TOP_VERTEX &&
3001             theFixedNodes.find( node ) == theFixedNodes.end())
3002         {
3003           // check if all faces around the node are on faceSubMesh
3004           // because a node on edge may be bound to face
3005           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3006           bool all = true;
3007           if ( faceSubMesh ) {
3008             while ( eIt->more() && all ) {
3009               const SMDS_MeshElement* e = eIt->next();
3010               all = faceSubMesh->Contains( e );
3011             }
3012           }
3013           if ( all )
3014             setMovableNodes.insert( node );
3015           else
3016             checkBoundaryNodes = true;
3017         }
3018         if ( posType == SMDS_TOP_3DSPACE )
3019           checkBoundaryNodes = true;
3020       }
3021
3022       if ( surface.IsNull() )
3023         continue;
3024
3025       // get nodes to check UV
3026       list< const SMDS_MeshNode* > uvCheckNodes;
3027       itN = elem->nodesIterator();
3028       nn = 0; nbn =  elem->NbNodes();
3029       if(elem->IsQuadratic())
3030         nbn = nbn/2;
3031       while ( nn++ < nbn ) {
3032         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3033         if ( uvMap.find( node ) == uvMap.end() )
3034           uvCheckNodes.push_back( node );
3035         // add nodes of elems sharing node
3036         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3037         //         while ( eIt->more() ) {
3038         //           const SMDS_MeshElement* e = eIt->next();
3039         //           if ( e != elem ) {
3040         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3041         //             while ( nIt->more() ) {
3042         //               const SMDS_MeshNode* n =
3043         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3044         //               if ( uvMap.find( n ) == uvMap.end() )
3045         //                 uvCheckNodes.push_back( n );
3046         //             }
3047         //           }
3048         //         }
3049       }
3050       // check UV on face
3051       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3052       for ( ; n != uvCheckNodes.end(); ++n ) {
3053         node = *n;
3054         gp_XY uv( 0, 0 );
3055         const SMDS_PositionPtr& pos = node->GetPosition();
3056         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3057         // get existing UV
3058         switch ( posType ) {
3059         case SMDS_TOP_FACE: {
3060           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3061           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3062           break;
3063         }
3064         case SMDS_TOP_EDGE: {
3065           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3066           Handle(Geom2d_Curve) pcurve;
3067           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3068             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3069           if ( !pcurve.IsNull() ) {
3070             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3071             uv = pcurve->Value( u ).XY();
3072           }
3073           break;
3074         }
3075         case SMDS_TOP_VERTEX: {
3076           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3077           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3078             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3079           break;
3080         }
3081         default:;
3082         }
3083         // check existing UV
3084         bool project = true;
3085         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3086         double dist1 = DBL_MAX, dist2 = 0;
3087         if ( posType != SMDS_TOP_3DSPACE ) {
3088           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3089           project = dist1 > fToler2;
3090         }
3091         if ( project ) { // compute new UV
3092           gp_XY newUV;
3093           if ( !getClosestUV( projector, pNode, newUV )) {
3094             MESSAGE("Node Projection Failed " << node);
3095           }
3096           else {
3097             if ( isUPeriodic )
3098               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3099             if ( isVPeriodic )
3100               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3101             // check new UV
3102             if ( posType != SMDS_TOP_3DSPACE )
3103               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3104             if ( dist2 < dist1 )
3105               uv = newUV;
3106           }
3107         }
3108         // store UV in the map
3109         listUV.push_back( uv );
3110         uvMap.insert( make_pair( node, &listUV.back() ));
3111       }
3112     } // loop on not yet smoothed elements
3113
3114     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3115       checkBoundaryNodes = true;
3116
3117     // fix nodes on mesh boundary
3118
3119     if ( checkBoundaryNodes ) {
3120       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3121       map< SMESH_TLink, int >::iterator link_nb;
3122       // put all elements links to linkNbMap
3123       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3124       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3125         const SMDS_MeshElement* elem = (*elemIt);
3126         int nbn =  elem->NbCornerNodes();
3127         // loop on elem links: insert them in linkNbMap
3128         for ( int iN = 0; iN < nbn; ++iN ) {
3129           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3130           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3131           SMESH_TLink link( n1, n2 );
3132           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3133           link_nb->second++;
3134         }
3135       }
3136       // remove nodes that are in links encountered only once from setMovableNodes
3137       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3138         if ( link_nb->second == 1 ) {
3139           setMovableNodes.erase( link_nb->first.node1() );
3140           setMovableNodes.erase( link_nb->first.node2() );
3141         }
3142       }
3143     }
3144
3145     // -----------------------------------------------------
3146     // for nodes on seam edge, compute one more UV ( uvMap2 );
3147     // find movable nodes linked to nodes on seam and which
3148     // are to be smoothed using the second UV ( uvMap2 )
3149     // -----------------------------------------------------
3150
3151     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3152     if ( !surface.IsNull() ) {
3153       TopExp_Explorer eExp( face, TopAbs_EDGE );
3154       for ( ; eExp.More(); eExp.Next() ) {
3155         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3156         if ( !BRep_Tool::IsClosed( edge, face ))
3157           continue;
3158         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3159         if ( !sm ) continue;
3160         // find out which parameter varies for a node on seam
3161         double f,l;
3162         gp_Pnt2d uv1, uv2;
3163         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3164         if ( pcurve.IsNull() ) continue;
3165         uv1 = pcurve->Value( f );
3166         edge.Reverse();
3167         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3168         if ( pcurve.IsNull() ) continue;
3169         uv2 = pcurve->Value( f );
3170         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3171         // assure uv1 < uv2
3172         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3173           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3174         }
3175         // get nodes on seam and its vertices
3176         list< const SMDS_MeshNode* > seamNodes;
3177         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3178         while ( nSeamIt->more() ) {
3179           const SMDS_MeshNode* node = nSeamIt->next();
3180           if ( !isQuadratic || !IsMedium( node ))
3181             seamNodes.push_back( node );
3182         }
3183         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3184         for ( ; vExp.More(); vExp.Next() ) {
3185           sm = aMesh->MeshElements( vExp.Current() );
3186           if ( sm ) {
3187             nSeamIt = sm->GetNodes();
3188             while ( nSeamIt->more() )
3189               seamNodes.push_back( nSeamIt->next() );
3190           }
3191         }
3192         // loop on nodes on seam
3193         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3194         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3195           const SMDS_MeshNode* nSeam = *noSeIt;
3196           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3197           if ( n_uv == uvMap.end() )
3198             continue;
3199           // set the first UV
3200           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3201           // set the second UV
3202           listUV.push_back( *n_uv->second );
3203           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3204           if ( uvMap2.empty() )
3205             uvMap2 = uvMap; // copy the uvMap contents
3206           uvMap2[ nSeam ] = &listUV.back();
3207
3208           // collect movable nodes linked to ones on seam in nodesNearSeam
3209           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3210           while ( eIt->more() ) {
3211             const SMDS_MeshElement* e = eIt->next();
3212             int nbUseMap1 = 0, nbUseMap2 = 0;
3213             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3214             int nn = 0, nbn =  e->NbNodes();
3215             if(e->IsQuadratic()) nbn = nbn/2;
3216             while ( nn++ < nbn )
3217             {
3218               const SMDS_MeshNode* n =
3219                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3220               if (n == nSeam ||
3221                   setMovableNodes.find( n ) == setMovableNodes.end() )
3222                 continue;
3223               // add only nodes being closer to uv2 than to uv1
3224               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3225                            0.5 * ( n->Y() + nSeam->Y() ),
3226                            0.5 * ( n->Z() + nSeam->Z() ));
3227               gp_XY uv;
3228               getClosestUV( projector, pMid, uv );
3229               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3230                 nodesNearSeam.insert( n );
3231                 nbUseMap2++;
3232               }
3233               else
3234                 nbUseMap1++;
3235             }
3236             // for centroidalSmooth all element nodes must
3237             // be on one side of a seam
3238             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3239               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3240               nn = 0;
3241               while ( nn++ < nbn ) {
3242                 const SMDS_MeshNode* n =
3243                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3244                 setMovableNodes.erase( n );
3245               }
3246             }
3247           }
3248         } // loop on nodes on seam
3249       } // loop on edge of a face
3250     } // if ( !face.IsNull() )
3251
3252     if ( setMovableNodes.empty() ) {
3253       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3254       continue; // goto next face
3255     }
3256
3257     // -------------
3258     // SMOOTHING //
3259     // -------------
3260
3261     int it = -1;
3262     double maxRatio = -1., maxDisplacement = -1.;
3263     set<const SMDS_MeshNode*>::iterator nodeToMove;
3264     for ( it = 0; it < theNbIterations; it++ ) {
3265       maxDisplacement = 0.;
3266       nodeToMove = setMovableNodes.begin();
3267       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3268         const SMDS_MeshNode* node = (*nodeToMove);
3269         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3270
3271         // smooth
3272         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3273         if ( theSmoothMethod == LAPLACIAN )
3274           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3275         else
3276           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3277
3278         // node displacement
3279         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3280         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3281         if ( aDispl > maxDisplacement )
3282           maxDisplacement = aDispl;
3283       }
3284       // no node movement => exit
3285       //if ( maxDisplacement < 1.e-16 ) {
3286       if ( maxDisplacement < disttol ) {
3287         MESSAGE("-- no node movement --");
3288         break;
3289       }
3290
3291       // check elements quality
3292       maxRatio  = 0;
3293       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3294       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3295         const SMDS_MeshElement* elem = (*elemIt);
3296         if ( !elem || elem->GetType() != SMDSAbs_Face )
3297           continue;
3298         SMESH::Controls::TSequenceOfXYZ aPoints;
3299         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3300           double aValue = aQualityFunc.GetValue( aPoints );
3301           if ( aValue > maxRatio )
3302             maxRatio = aValue;
3303         }
3304       }
3305       if ( maxRatio <= theTgtAspectRatio ) {
3306         MESSAGE("-- quality achived --");
3307         break;
3308       }
3309       if (it+1 == theNbIterations) {
3310         MESSAGE("-- Iteration limit exceeded --");
3311       }
3312     } // smoothing iterations
3313
3314     MESSAGE(" Face id: " << *fId <<
3315             " Nb iterstions: " << it <<
3316             " Displacement: " << maxDisplacement <<
3317             " Aspect Ratio " << maxRatio);
3318
3319     // ---------------------------------------
3320     // new nodes positions are computed,
3321     // record movement in DS and set new UV
3322     // ---------------------------------------
3323     nodeToMove = setMovableNodes.begin();
3324     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3325       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3326       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3327       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3328       if ( node_uv != uvMap.end() ) {
3329         gp_XY* uv = node_uv->second;
3330         node->SetPosition
3331           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3332       }
3333     }
3334
3335     // move medium nodes of quadratic elements
3336     if ( isQuadratic )
3337     {
3338       SMESH_MesherHelper helper( *GetMesh() );
3339       if ( !face.IsNull() )
3340         helper.SetSubShape( face );
3341       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3342       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3343         const SMDS_VtkFace* QF =
3344           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3345         if(QF && QF->IsQuadratic()) {
3346           vector<const SMDS_MeshNode*> Ns;
3347           Ns.reserve(QF->NbNodes()+1);
3348           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3349           while ( anIter->more() )
3350             Ns.push_back( cast2Node(anIter->next()) );
3351           Ns.push_back( Ns[0] );
3352           double x, y, z;
3353           for(int i=0; i<QF->NbNodes(); i=i+2) {
3354             if ( !surface.IsNull() ) {
3355               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3356               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3357               gp_XY uv = ( uv1 + uv2 ) / 2.;
3358               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3359               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3360             }
3361             else {
3362               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3363               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3364               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3365             }
3366             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3367                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3368                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3369               // we have to move i+1 node
3370               aMesh->MoveNode( Ns[i+1], x, y, z );
3371             }
3372           }
3373         }
3374       }
3375     }
3376
3377   } // loop on face ids
3378
3379 }
3380
3381 //=======================================================================
3382 //function : isReverse
3383 //purpose  : Return true if normal of prevNodes is not co-directied with
3384 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3385 //           iNotSame is where prevNodes and nextNodes are different
3386 //=======================================================================
3387
3388 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3389                       vector<const SMDS_MeshNode*> nextNodes,
3390                       const int            nbNodes,
3391                       const int            iNotSame)
3392 {
3393   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3394   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3395
3396   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3397   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3398   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3399   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3400
3401   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3402   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3403   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3404   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3405
3406   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3407
3408   return (vA ^ vB) * vN < 0.0;
3409 }
3410
3411 //=======================================================================
3412 /*!
3413  * \brief Create elements by sweeping an element
3414  * \param elem - element to sweep
3415  * \param newNodesItVec - nodes generated from each node of the element
3416  * \param newElems - generated elements
3417  * \param nbSteps - number of sweeping steps
3418  * \param srcElements - to append elem for each generated element
3419  */
3420 //=======================================================================
3421
3422 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3423                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3424                                     list<const SMDS_MeshElement*>&        newElems,
3425                                     const int                             nbSteps,
3426                                     SMESH_SequenceOfElemPtr&              srcElements)
3427 {
3428   //MESSAGE("sweepElement " << nbSteps);
3429   SMESHDS_Mesh* aMesh = GetMeshDS();
3430
3431   // Loop on elem nodes:
3432   // find new nodes and detect same nodes indices
3433   int nbNodes = elem->NbNodes();
3434   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3435   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3436   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3437   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3438
3439   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3440   vector<int> sames(nbNodes);
3441   vector<bool> issimple(nbNodes);
3442
3443   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3444     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3445     const SMDS_MeshNode*                 node         = nnIt->first;
3446     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3447     if ( listNewNodes.empty() ) {
3448       return;
3449     }
3450
3451     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3452
3453     itNN[ iNode ] = listNewNodes.begin();
3454     prevNod[ iNode ] = node;
3455     nextNod[ iNode ] = listNewNodes.front();
3456     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3457       if ( prevNod[ iNode ] != nextNod [ iNode ])
3458         iNotSameNode = iNode;
3459       else {
3460         iSameNode = iNode;
3461         //nbSame++;
3462         sames[nbSame++] = iNode;
3463       }
3464     }
3465   }
3466
3467   //cerr<<"  nbSame = "<<nbSame<<endl;
3468   if ( nbSame == nbNodes || nbSame > 2) {
3469     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3470     //INFOS( " Too many same nodes of element " << elem->GetID() );
3471     return;
3472   }
3473
3474   //  if( elem->IsQuadratic() && nbSame>0 ) {
3475   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3476   //    return;
3477   //  }
3478
3479   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3480   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3481   if ( nbSame > 0 ) {
3482     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3483     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3484     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3485   }
3486
3487   //if(nbNodes==8)
3488   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3489   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3490   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3491   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3492
3493   // check element orientation
3494   int i0 = 0, i2 = 2;
3495   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3496     //MESSAGE("Reversed elem " << elem );
3497     i0 = 2;
3498     i2 = 0;
3499     if ( nbSame > 0 )
3500       std::swap( iBeforeSame, iAfterSame );
3501   }
3502
3503   // make new elements
3504   const SMDS_MeshElement* lastElem = elem;
3505   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3506     // get next nodes
3507     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3508       if(issimple[iNode]) {
3509         nextNod[ iNode ] = *itNN[ iNode ];
3510         itNN[ iNode ]++;
3511       }
3512       else {
3513         if( elem->GetType()==SMDSAbs_Node ) {
3514           // we have to use two nodes
3515           midlNod[ iNode ] = *itNN[ iNode ];
3516           itNN[ iNode ]++;
3517           nextNod[ iNode ] = *itNN[ iNode ];
3518           itNN[ iNode ]++;
3519         }
3520         else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3521           // we have to use each second node
3522           //itNN[ iNode ]++;
3523           nextNod[ iNode ] = *itNN[ iNode ];
3524           itNN[ iNode ]++;
3525         }
3526         else {
3527           // we have to use two nodes
3528           midlNod[ iNode ] = *itNN[ iNode ];
3529           itNN[ iNode ]++;
3530           nextNod[ iNode ] = *itNN[ iNode ];
3531           itNN[ iNode ]++;
3532         }
3533       }
3534     }
3535     SMDS_MeshElement* aNewElem = 0;
3536     if(!elem->IsPoly()) {
3537       switch ( nbNodes ) {
3538       case 0:
3539         return;
3540       case 1: { // NODE
3541         if ( nbSame == 0 ) {
3542           if(issimple[0])
3543             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3544           else
3545             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3546         }
3547         break;
3548       }
3549       case 2: { // EDGE
3550         if ( nbSame == 0 )
3551           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3552                                     nextNod[ 1 ], nextNod[ 0 ] );
3553         else
3554           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3555                                     nextNod[ iNotSameNode ] );
3556         break;
3557       }
3558
3559       case 3: { // TRIANGLE or quadratic edge
3560         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3561
3562           if ( nbSame == 0 )       // --- pentahedron
3563             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3564                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3565
3566           else if ( nbSame == 1 )  // --- pyramid
3567             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3568                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3569                                          nextNod[ iSameNode ]);
3570
3571           else // 2 same nodes:      --- tetrahedron
3572             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3573                                          nextNod[ iNotSameNode ]);
3574         }
3575         else { // quadratic edge
3576           if(nbSame==0) {     // quadratic quadrangle
3577             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3578                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3579           }
3580           else if(nbSame==1) { // quadratic triangle
3581             if(sames[0]==2) {
3582               return; // medium node on axis
3583             }
3584             else if(sames[0]==0) {
3585               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3586                                         nextNod[2], midlNod[1], prevNod[2]);
3587             }
3588             else { // sames[0]==1
3589               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3590                                         midlNod[0], nextNod[2], prevNod[2]);
3591             }
3592           }
3593           else {
3594             return;
3595           }
3596         }
3597         break;
3598       }
3599       case 4: { // QUADRANGLE
3600
3601         if ( nbSame == 0 )       // --- hexahedron
3602           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3603                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3604
3605         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3606           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3607                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3608                                        nextNod[ iSameNode ]);
3609           newElems.push_back( aNewElem );
3610           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3611                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3612                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3613         }
3614         else if ( nbSame == 2 ) { // pentahedron
3615           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3616             // iBeforeSame is same too
3617             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3618                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3619                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3620           else
3621             // iAfterSame is same too
3622             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3623                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3624                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3625         }
3626         break;
3627       }
3628       case 6: { // quadratic triangle
3629         // create pentahedron with 15 nodes
3630         if(nbSame==0) {
3631           if(i0>0) { // reversed case
3632             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3633                                          nextNod[0], nextNod[2], nextNod[1],
3634                                          prevNod[5], prevNod[4], prevNod[3],
3635                                          nextNod[5], nextNod[4], nextNod[3],
3636                                          midlNod[0], midlNod[2], midlNod[1]);
3637           }
3638           else { // not reversed case
3639             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3640                                          nextNod[0], nextNod[1], nextNod[2],
3641                                          prevNod[3], prevNod[4], prevNod[5],
3642                                          nextNod[3], nextNod[4], nextNod[5],
3643                                          midlNod[0], midlNod[1], midlNod[2]);
3644           }
3645         }
3646         else if(nbSame==1) {
3647           // 2d order pyramid of 13 nodes
3648           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3649           //                                 int n12,int n23,int n34,int n41,
3650           //                                 int n15,int n25,int n35,int n45, int ID);
3651           int n5 = iSameNode;
3652           int n1,n4,n41,n15,n45;
3653           if(i0>0) { // reversed case
3654             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3655             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3656             n41 = n1 + 3;
3657             n15 = n5 + 3;
3658             n45 = n4 + 3;
3659           }
3660           else {
3661             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3662             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3663             n41 = n4 + 3;
3664             n15 = n1 + 3;
3665             n45 = n5 + 3;
3666           }
3667           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3668                                       nextNod[n4], prevNod[n4], prevNod[n5],
3669                                       midlNod[n1], nextNod[n41],
3670                                       midlNod[n4], prevNod[n41],
3671                                       prevNod[n15], nextNod[n15],
3672                                       nextNod[n45], prevNod[n45]);
3673         }
3674         else if(nbSame==2) {
3675           // 2d order tetrahedron of 10 nodes
3676           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3677           //                                 int n12,int n23,int n31,
3678           //                                 int n14,int n24,int n34, int ID);
3679           int n1 = iNotSameNode;
3680           int n2,n3,n12,n23,n31;
3681           if(i0>0) { // reversed case
3682             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3683             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3684             n12 = n2 + 3;
3685             n23 = n3 + 3;
3686             n31 = n1 + 3;
3687           }
3688           else {
3689             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3690             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3691             n12 = n1 + 3;
3692             n23 = n2 + 3;
3693             n31 = n3 + 3;
3694           }
3695           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3696                                        prevNod[n12], prevNod[n23], prevNod[n31],
3697                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3698         }
3699         break;
3700       }
3701       case 8: { // quadratic quadrangle
3702         if(nbSame==0) {
3703           // create hexahedron with 20 nodes
3704           if(i0>0) { // reversed case
3705             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3706                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3707                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3708                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3709                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3710           }
3711           else { // not reversed case
3712             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3713                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3714                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3715                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3716                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3717           }
3718         }
3719         else if(nbSame==1) { 
3720           // --- pyramid + pentahedron - can not be created since it is needed 
3721           // additional middle node ot the center of face
3722           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3723           return;
3724         }
3725         else if(nbSame==2) {
3726           // 2d order Pentahedron with 15 nodes
3727           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3728           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3729           //                                 int n14,int n25,int n36, int ID);
3730           int n1,n2,n4,n5;
3731           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3732             // iBeforeSame is same too
3733             n1 = iBeforeSame;
3734             n2 = iOpposSame;
3735             n4 = iSameNode;
3736             n5 = iAfterSame;
3737           }
3738           else {
3739             // iAfterSame is same too
3740             n1 = iSameNode;
3741             n2 = iBeforeSame;
3742             n4 = iAfterSame;
3743             n5 = iOpposSame;
3744           }
3745           int n12,n45,n14,n25;
3746           if(i0>0) { //reversed case
3747             n12 = n1 + 4;
3748             n45 = n5 + 4;
3749             n14 = n4 + 4;
3750             n25 = n2 + 4;
3751           }
3752           else {
3753             n12 = n2 + 4;
3754             n45 = n4 + 4;
3755             n14 = n1 + 4;
3756             n25 = n5 + 4;
3757           }
3758           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3759                                        prevNod[n4], prevNod[n5], nextNod[n5],
3760                                        prevNod[n12], midlNod[n2], nextNod[n12],
3761                                        prevNod[n45], midlNod[n5], nextNod[n45],
3762                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3763         }
3764         break;
3765       }
3766       default: {
3767         // realized for extrusion only
3768         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3769         //vector<int> quantities (nbNodes + 2);
3770
3771         //quantities[0] = nbNodes; // bottom of prism
3772         //for (int inode = 0; inode < nbNodes; inode++) {
3773         //  polyedre_nodes[inode] = prevNod[inode];
3774         //}
3775
3776         //quantities[1] = nbNodes; // top of prism
3777         //for (int inode = 0; inode < nbNodes; inode++) {
3778         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3779         //}
3780
3781         //for (int iface = 0; iface < nbNodes; iface++) {
3782         //  quantities[iface + 2] = 4;
3783         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3784         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3785         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3786         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3787         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3788         //}
3789         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3790         break;
3791       }
3792       }
3793     }
3794
3795     if(!aNewElem) {
3796       // realized for extrusion only
3797       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3798       vector<int> quantities (nbNodes + 2);
3799
3800       quantities[0] = nbNodes; // bottom of prism
3801       for (int inode = 0; inode < nbNodes; inode++) {
3802         polyedre_nodes[inode] = prevNod[inode];
3803       }
3804
3805       quantities[1] = nbNodes; // top of prism
3806       for (int inode = 0; inode < nbNodes; inode++) {
3807         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3808       }
3809
3810       for (int iface = 0; iface < nbNodes; iface++) {
3811         quantities[iface + 2] = 4;
3812         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3813         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3814         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3815         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3816         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3817       }
3818       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3819     }
3820
3821     if ( aNewElem ) {
3822       newElems.push_back( aNewElem );
3823       myLastCreatedElems.Append(aNewElem);
3824       srcElements.Append( elem );
3825       lastElem = aNewElem;
3826     }
3827
3828     // set new prev nodes
3829     for ( iNode = 0; iNode < nbNodes; iNode++ )
3830       prevNod[ iNode ] = nextNod[ iNode ];
3831
3832   } // for steps
3833 }
3834
3835 //=======================================================================
3836 /*!
3837  * \brief Create 1D and 2D elements around swept elements
3838  * \param mapNewNodes - source nodes and ones generated from them
3839  * \param newElemsMap - source elements and ones generated from them
3840  * \param elemNewNodesMap - nodes generated from each node of each element
3841  * \param elemSet - all swept elements
3842  * \param nbSteps - number of sweeping steps
3843  * \param srcElements - to append elem for each generated element
3844  */
3845 //=======================================================================
3846
3847 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3848                                   TElemOfElemListMap &     newElemsMap,
3849                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3850                                   TIDSortedElemSet&        elemSet,
3851                                   const int                nbSteps,
3852                                   SMESH_SequenceOfElemPtr& srcElements)
3853 {
3854   MESSAGE("makeWalls");
3855   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3856   SMESHDS_Mesh* aMesh = GetMeshDS();
3857
3858   // Find nodes belonging to only one initial element - sweep them to get edges.
3859
3860   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3861   for ( ; nList != mapNewNodes.end(); nList++ ) {
3862     const SMDS_MeshNode* node =
3863       static_cast<const SMDS_MeshNode*>( nList->first );
3864     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3865     int nbInitElems = 0;
3866     const SMDS_MeshElement* el = 0;
3867     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3868     while ( eIt->more() && nbInitElems < 2 ) {
3869       el = eIt->next();
3870       SMDSAbs_ElementType type = el->GetType();
3871       if ( type == SMDSAbs_Volume || type < highType ) continue;
3872       if ( type > highType ) {
3873         nbInitElems = 0;
3874         highType = type;
3875       }
3876       if ( elemSet.find(el) != elemSet.end() )
3877         nbInitElems++;
3878     }
3879     if ( nbInitElems < 2 ) {
3880       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3881       if(!NotCreateEdge) {
3882         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3883         list<const SMDS_MeshElement*> newEdges;
3884         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3885       }
3886     }
3887   }
3888
3889   // Make a ceiling for each element ie an equal element of last new nodes.
3890   // Find free links of faces - make edges and sweep them into faces.
3891
3892   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3893   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3894   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3895     const SMDS_MeshElement* elem = itElem->first;
3896     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3897
3898     if(itElem->second.size()==0) continue;
3899
3900     if ( elem->GetType() == SMDSAbs_Edge ) {
3901       // create a ceiling edge
3902       if (!elem->IsQuadratic()) {
3903         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3904                                vecNewNodes[ 1 ]->second.back())) {
3905           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3906                                                    vecNewNodes[ 1 ]->second.back()));
3907           srcElements.Append( myLastCreatedElems.Last() );
3908         }
3909       }
3910       else {
3911         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3912                                vecNewNodes[ 1 ]->second.back(),
3913                                vecNewNodes[ 2 ]->second.back())) {
3914           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3915                                                    vecNewNodes[ 1 ]->second.back(),
3916                                                    vecNewNodes[ 2 ]->second.back()));
3917           srcElements.Append( myLastCreatedElems.Last() );
3918         }
3919       }
3920     }
3921     if ( elem->GetType() != SMDSAbs_Face )
3922       continue;
3923
3924     bool hasFreeLinks = false;
3925
3926     TIDSortedElemSet avoidSet;
3927     avoidSet.insert( elem );
3928
3929     set<const SMDS_MeshNode*> aFaceLastNodes;
3930     int iNode, nbNodes = vecNewNodes.size();
3931     if(!elem->IsQuadratic()) {
3932       // loop on the face nodes
3933       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3934         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3935         // look for free links of the face
3936         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3937         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3938         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3939         // check if a link is free
3940         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3941           hasFreeLinks = true;
3942           // make an edge and a ceiling for a new edge
3943           if ( !aMesh->FindEdge( n1, n2 )) {
3944             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3945             srcElements.Append( myLastCreatedElems.Last() );
3946           }
3947           n1 = vecNewNodes[ iNode ]->second.back();
3948           n2 = vecNewNodes[ iNext ]->second.back();
3949           if ( !aMesh->FindEdge( n1, n2 )) {
3950             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3951             srcElements.Append( myLastCreatedElems.Last() );
3952           }
3953         }
3954       }
3955     }
3956     else { // elem is quadratic face
3957       int nbn = nbNodes/2;
3958       for ( iNode = 0; iNode < nbn; iNode++ ) {
3959         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3960         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3961         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3962         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3963         // check if a link is free
3964         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3965           hasFreeLinks = true;
3966           // make an edge and a ceiling for a new edge
3967           // find medium node
3968           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3969           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3970             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3971             srcElements.Append( myLastCreatedElems.Last() );
3972           }
3973           n1 = vecNewNodes[ iNode ]->second.back();
3974           n2 = vecNewNodes[ iNext ]->second.back();
3975           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3976           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3977             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3978             srcElements.Append( myLastCreatedElems.Last() );
3979           }
3980         }
3981       }
3982       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3983         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3984       }
3985     }
3986
3987     // sweep free links into faces
3988
3989     if ( hasFreeLinks )  {
3990       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3991       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3992
3993       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3994       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3995         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3996         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3997       }
3998       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3999         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4000         iVol = 0;
4001         while ( iVol++ < volNb ) v++;
4002         // find indices of free faces of a volume and their source edges
4003         list< int > freeInd;
4004         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4005         SMDS_VolumeTool vTool( *v );
4006         int iF, nbF = vTool.NbFaces();
4007         for ( iF = 0; iF < nbF; iF ++ ) {
4008           if (vTool.IsFreeFace( iF ) &&
4009               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4010               initNodeSet != faceNodeSet) // except an initial face
4011           {
4012             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4013               continue;
4014             freeInd.push_back( iF );
4015             // find source edge of a free face iF
4016             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4017             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4018             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4019                                    initNodeSet.begin(), initNodeSet.end(),
4020                                    commonNodes.begin());
4021             if ( (*v)->IsQuadratic() )
4022               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4023             else
4024               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4025 #ifdef _DEBUG_
4026             if ( !srcEdges.back() )
4027             {
4028               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4029                    << iF << " of volume #" << vTool.ID() << endl;
4030             }
4031 #endif
4032           }
4033         }
4034         if ( freeInd.empty() )
4035           continue;
4036
4037         // create faces for all steps;
4038         // if such a face has been already created by sweep of edge,
4039         // assure that its orientation is OK
4040         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
4041           vTool.Set( *v );
4042           vTool.SetExternalNormal();
4043           const int nextShift = vTool.IsForward() ? +1 : -1;
4044           list< int >::iterator ind = freeInd.begin();
4045           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4046           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4047           {
4048             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4049             int nbn = vTool.NbFaceNodes( *ind );
4050             if ( ! (*v)->IsPoly() )
4051               switch ( nbn ) {
4052               case 3: { ///// triangle
4053                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4054                 if ( !f ||
4055                      nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4056                 {
4057                   const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4058                                                        nodes[ 1 ],
4059                                                        nodes[ 1 + nextShift ] };
4060                   if ( f )
4061                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4062                   else
4063                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4064                                                               newOrder[ 2 ] ));
4065                 }
4066                 break;
4067               }
4068               case 4: { ///// quadrangle
4069                 const SMDS_MeshFace * f =
4070                   aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4071                 if ( !f ||
4072                      nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4073                 {
4074                   const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4075                                                        nodes[ 2 ], nodes[ 2+nextShift ] };
4076                   if ( f )
4077                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4078                   else
4079                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4080                                                               newOrder[ 2 ], newOrder[ 3 ]));
4081                 }
4082                 break;
4083               }
4084               case 6: { /////// quadratic triangle
4085                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4086                                                            nodes[1], nodes[3], nodes[5] );
4087                 if ( !f ||
4088                      nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4089                 {
4090                   const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4091                                                        nodes[2],
4092                                                        nodes[2 + 2*nextShift],
4093                                                        nodes[3 - 2*nextShift],
4094                                                        nodes[3],
4095                                                        nodes[3 + 2*nextShift]};
4096                   if ( f )
4097                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4098                   else
4099                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4100                                                               newOrder[ 1 ],
4101                                                               newOrder[ 2 ],
4102                                                               newOrder[ 3 ],
4103                                                               newOrder[ 4 ],
4104                                                               newOrder[ 5 ] ));
4105                 }
4106                 break;
4107               }
4108               default:       /////// quadratic quadrangle
4109                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4110                                                            nodes[1], nodes[3], nodes[5], nodes[7] );
4111                 if ( !f ||
4112                      nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4113                 {
4114                   const SMDS_MeshNode* newOrder[8] = { nodes[0],
4115                                                        nodes[4 - 2*nextShift],
4116                                                        nodes[4],
4117                                                        nodes[4 + 2*nextShift],
4118                                                        nodes[1],
4119                                                        nodes[5 - 2*nextShift],
4120                                                        nodes[5],
4121                                                        nodes[5 + 2*nextShift] };
4122                   if ( f )
4123                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4124                   else
4125                     myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4126                                                              newOrder[ 2 ], newOrder[ 3 ],
4127                                                              newOrder[ 4 ], newOrder[ 5 ],
4128                                                              newOrder[ 6 ], newOrder[ 7 ]));
4129                 }
4130               } // switch ( nbn )
4131
4132             else { //////// polygon
4133
4134               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4135               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4136               if ( !f ||
4137                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4138               {
4139                 if ( !vTool.IsForward() )
4140                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4141                 if ( f )
4142                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4143                 else
4144                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4145               }
4146             }
4147
4148             while ( srcElements.Length() < myLastCreatedElems.Length() )
4149               srcElements.Append( *srcEdge );
4150
4151           }  // loop on free faces
4152
4153           // go to the next volume
4154           iVol = 0;
4155           while ( iVol++ < nbVolumesByStep ) v++;
4156
4157         } // loop on steps
4158       } // loop on volumes of one step
4159     } // sweep free links into faces
4160
4161     // Make a ceiling face with a normal external to a volume
4162
4163     SMDS_VolumeTool lastVol( itElem->second.back() );
4164
4165     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4166     if ( iF >= 0 ) {
4167       lastVol.SetExternalNormal();
4168       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4169       int nbn = lastVol.NbFaceNodes( iF );
4170       switch ( nbn ) {
4171       case 3:
4172         if (!hasFreeLinks ||
4173             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4174           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4175         break;
4176       case 4:
4177         if (!hasFreeLinks ||
4178             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4179           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4180         break;
4181       default:
4182         if(itElem->second.back()->IsQuadratic()) {
4183           if(nbn==6) {
4184             if (!hasFreeLinks ||
4185                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4186                                  nodes[1], nodes[3], nodes[5]) ) {
4187               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4188                                                        nodes[1], nodes[3], nodes[5]));
4189             }
4190           }
4191           else { // nbn==8
4192             if (!hasFreeLinks ||
4193                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4194                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4195               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4196                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4197           }
4198         }
4199         else {
4200           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4201           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4202             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4203         }
4204       } // switch
4205
4206       while ( srcElements.Length() < myLastCreatedElems.Length() )
4207         srcElements.Append( myLastCreatedElems.Last() );
4208     }
4209   } // loop on swept elements
4210 }
4211
4212 //=======================================================================
4213 //function : RotationSweep
4214 //purpose  :
4215 //=======================================================================
4216
4217 SMESH_MeshEditor::PGroupIDs
4218 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4219                                 const gp_Ax1&      theAxis,
4220                                 const double       theAngle,
4221                                 const int          theNbSteps,
4222                                 const double       theTol,
4223                                 const bool         theMakeGroups,
4224                                 const bool         theMakeWalls)
4225 {
4226   myLastCreatedElems.Clear();
4227   myLastCreatedNodes.Clear();
4228
4229   // source elements for each generated one
4230   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4231
4232   MESSAGE( "RotationSweep()");
4233   gp_Trsf aTrsf;
4234   aTrsf.SetRotation( theAxis, theAngle );
4235   gp_Trsf aTrsf2;
4236   aTrsf2.SetRotation( theAxis, theAngle/2. );
4237
4238   gp_Lin aLine( theAxis );
4239   double aSqTol = theTol * theTol;
4240
4241   SMESHDS_Mesh* aMesh = GetMeshDS();
4242
4243   TNodeOfNodeListMap mapNewNodes;
4244   TElemOfVecOfNnlmiMap mapElemNewNodes;
4245   TElemOfElemListMap newElemsMap;
4246
4247   // loop on theElems
4248   TIDSortedElemSet::iterator itElem;
4249   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4250     const SMDS_MeshElement* elem = *itElem;
4251     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4252       continue;
4253     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4254     newNodesItVec.reserve( elem->NbNodes() );
4255
4256     // loop on elem nodes
4257     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4258     while ( itN->more() ) {
4259       // check if a node has been already sweeped
4260       const SMDS_MeshNode* node = cast2Node( itN->next() );
4261
4262       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4263       double coord[3];
4264       aXYZ.Coord( coord[0], coord[1], coord[2] );
4265       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4266
4267       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4268       if ( nIt == mapNewNodes.end() ) {
4269         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4270         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4271
4272         // make new nodes
4273         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4274         //double coord[3];
4275         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4276         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4277         const SMDS_MeshNode * newNode = node;
4278         for ( int i = 0; i < theNbSteps; i++ ) {
4279           if ( !isOnAxis ) {
4280             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4281               // create two nodes
4282               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4283               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4284               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4285               myLastCreatedNodes.Append(newNode);
4286               srcNodes.Append( node );
4287               listNewNodes.push_back( newNode );
4288               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4289               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4290             }
4291             else {
4292               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4293             }
4294             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4295             myLastCreatedNodes.Append(newNode);
4296             srcNodes.Append( node );
4297             listNewNodes.push_back( newNode );
4298           }
4299           else {
4300             listNewNodes.push_back( newNode );
4301             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4302               listNewNodes.push_back( newNode );
4303             }
4304           }
4305         }
4306       }
4307       /*
4308         else {
4309         // if current elem is quadratic and current node is not medium
4310         // we have to check - may be it is needed to insert additional nodes
4311         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4312         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4313         if(listNewNodes.size()==theNbSteps) {
4314         listNewNodes.clear();
4315         // make new nodes
4316         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4317         //double coord[3];
4318         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4319         const SMDS_MeshNode * newNode = node;
4320         if ( !isOnAxis ) {
4321         for(int i = 0; i<theNbSteps; i++) {
4322         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4323         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4324         cout<<"    3 AddNode:  "<<newNode;
4325         myLastCreatedNodes.Append(newNode);
4326         listNewNodes.push_back( newNode );
4327         srcNodes.Append( node );
4328         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4329         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4330         cout<<"    4 AddNode:  "<<newNode;
4331         myLastCreatedNodes.Append(newNode);
4332         srcNodes.Append( node );
4333         listNewNodes.push_back( newNode );
4334         }
4335         }
4336         else {
4337         listNewNodes.push_back( newNode );
4338         }
4339         }
4340         }
4341         }
4342       */
4343       newNodesItVec.push_back( nIt );
4344     }
4345     // make new elements
4346     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4347   }
4348
4349   if ( theMakeWalls )
4350     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4351
4352   PGroupIDs newGroupIDs;
4353   if ( theMakeGroups )
4354     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4355
4356   return newGroupIDs;
4357 }
4358
4359
4360 //=======================================================================
4361 //function : CreateNode
4362 //purpose  :
4363 //=======================================================================
4364 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4365                                                   const double y,
4366                                                   const double z,
4367                                                   const double tolnode,
4368                                                   SMESH_SequenceOfNode& aNodes)
4369 {
4370   myLastCreatedElems.Clear();
4371   myLastCreatedNodes.Clear();
4372
4373   gp_Pnt P1(x,y,z);
4374   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4375
4376   // try to search in sequence of existing nodes
4377   // if aNodes.Length()>0 we 'nave to use given sequence
4378   // else - use all nodes of mesh
4379   if(aNodes.Length()>0) {
4380     int i;
4381     for(i=1; i<=aNodes.Length(); i++) {
4382       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4383       if(P1.Distance(P2)<tolnode)
4384         return aNodes.Value(i);
4385     }
4386   }
4387   else {
4388     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4389     while(itn->more()) {
4390       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4391       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4392       if(P1.Distance(P2)<tolnode)
4393         return aN;
4394     }
4395   }
4396
4397   // create new node and return it
4398   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4399   myLastCreatedNodes.Append(NewNode);
4400   return NewNode;
4401 }
4402
4403
4404 //=======================================================================
4405 //function : ExtrusionSweep
4406 //purpose  :
4407 //=======================================================================
4408
4409 SMESH_MeshEditor::PGroupIDs
4410 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4411                                   const gp_Vec&       theStep,
4412                                   const int           theNbSteps,
4413                                   TElemOfElemListMap& newElemsMap,
4414                                   const bool          theMakeGroups,
4415                                   const int           theFlags,
4416                                   const double        theTolerance)
4417 {
4418   ExtrusParam aParams;
4419   aParams.myDir = gp_Dir(theStep);
4420   aParams.myNodes.Clear();
4421   aParams.mySteps = new TColStd_HSequenceOfReal;
4422   int i;
4423   for(i=1; i<=theNbSteps; i++)
4424     aParams.mySteps->Append(theStep.Magnitude());
4425
4426   return
4427     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4428 }
4429
4430
4431 //=======================================================================
4432 //function : ExtrusionSweep
4433 //purpose  :
4434 //=======================================================================
4435
4436 SMESH_MeshEditor::PGroupIDs
4437 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4438                                   ExtrusParam&        theParams,
4439                                   TElemOfElemListMap& newElemsMap,
4440                                   const bool          theMakeGroups,
4441                                   const int           theFlags,
4442                                   const double        theTolerance)
4443 {
4444   MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4445   myLastCreatedElems.Clear();
4446   myLastCreatedNodes.Clear();
4447
4448   // source elements for each generated one
4449   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4450
4451   SMESHDS_Mesh* aMesh = GetMeshDS();
4452
4453   int nbsteps = theParams.mySteps->Length();
4454
4455   TNodeOfNodeListMap mapNewNodes;
4456   //TNodeOfNodeVecMap mapNewNodes;
4457   TElemOfVecOfNnlmiMap mapElemNewNodes;
4458   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4459
4460   // loop on theElems
4461   TIDSortedElemSet::iterator itElem;
4462   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4463     // check element type
4464     const SMDS_MeshElement* elem = *itElem;
4465     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4466       continue;
4467
4468     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4469     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4470     newNodesItVec.reserve( elem->NbNodes() );
4471
4472     // loop on elem nodes
4473     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4474     while ( itN->more() )
4475     {
4476       // check if a node has been already sweeped
4477       const SMDS_MeshNode* node = cast2Node( itN->next() );
4478       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4479       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4480       if ( nIt == mapNewNodes.end() ) {
4481         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4482         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4483         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4484         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4485         //vecNewNodes.reserve(nbsteps);
4486
4487         // make new nodes
4488         double coord[] = { node->X(), node->Y(), node->Z() };
4489         //int nbsteps = theParams.mySteps->Length();
4490         for ( int i = 0; i < nbsteps; i++ ) {
4491           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4492             // create additional node
4493             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4494             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4495             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4496             if( theFlags & EXTRUSION_FLAG_SEW ) {
4497               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4498                                                          theTolerance, theParams.myNodes);
4499               listNewNodes.push_back( newNode );
4500             }
4501             else {
4502               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4503               myLastCreatedNodes.Append(newNode);
4504               srcNodes.Append( node );
4505               listNewNodes.push_back( newNode );
4506             }
4507           }
4508           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4509           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4510           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4511           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4512           if( theFlags & EXTRUSION_FLAG_SEW ) {
4513             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4514                                                        theTolerance, theParams.myNodes);
4515             listNewNodes.push_back( newNode );
4516             //vecNewNodes[i]=newNode;
4517           }
4518           else {
4519             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4520             myLastCreatedNodes.Append(newNode);
4521             srcNodes.Append( node );
4522             listNewNodes.push_back( newNode );
4523             //vecNewNodes[i]=newNode;
4524           }
4525         }
4526       }
4527       else {
4528         // if current elem is quadratic and current node is not medium
4529         // we have to check - may be it is needed to insert additional nodes
4530         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4531           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4532           if(listNewNodes.size()==nbsteps) {
4533             listNewNodes.clear();
4534             double coord[] = { node->X(), node->Y(), node->Z() };
4535             for ( int i = 0; i < nbsteps; i++ ) {
4536               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4537               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4538               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4539               if( theFlags & EXTRUSION_FLAG_SEW ) {
4540                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4541                                                            theTolerance, theParams.myNodes);
4542                 listNewNodes.push_back( newNode );
4543               }
4544               else {
4545                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4546                 myLastCreatedNodes.Append(newNode);
4547                 srcNodes.Append( node );
4548                 listNewNodes.push_back( newNode );
4549               }
4550               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4551               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4552               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4553               if( theFlags & EXTRUSION_FLAG_SEW ) {
4554                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4555                                                            theTolerance, theParams.myNodes);
4556                 listNewNodes.push_back( newNode );
4557               }
4558               else {
4559                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4560                 myLastCreatedNodes.Append(newNode);
4561                 srcNodes.Append( node );
4562                 listNewNodes.push_back( newNode );
4563               }
4564             }
4565           }
4566         }
4567       }
4568       newNodesItVec.push_back( nIt );
4569     }
4570     // make new elements
4571     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4572   }
4573
4574   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4575     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4576   }
4577   PGroupIDs newGroupIDs;
4578   if ( theMakeGroups )
4579     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4580
4581   return newGroupIDs;
4582 }
4583
4584 /*
4585 //=======================================================================
4586 //class    : SMESH_MeshEditor_PathPoint
4587 //purpose  : auxiliary class
4588 //=======================================================================
4589 class SMESH_MeshEditor_PathPoint {
4590 public:
4591 SMESH_MeshEditor_PathPoint() {
4592 myPnt.SetCoord(99., 99., 99.);
4593 myTgt.SetCoord(1.,0.,0.);
4594 myAngle=0.;
4595 myPrm=0.;
4596 }
4597 void SetPnt(const gp_Pnt& aP3D){
4598 myPnt=aP3D;
4599 }
4600 void SetTangent(const gp_Dir& aTgt){
4601 myTgt=aTgt;
4602 }
4603 void SetAngle(const double& aBeta){
4604 myAngle=aBeta;
4605 }
4606 void SetParameter(const double& aPrm){
4607 myPrm=aPrm;
4608 }
4609 const gp_Pnt& Pnt()const{
4610 return myPnt;
4611 }
4612 const gp_Dir& Tangent()const{
4613 return myTgt;
4614 }
4615 double Angle()const{
4616 return myAngle;
4617 }
4618 double Parameter()const{
4619 return myPrm;
4620 }
4621
4622 protected:
4623 gp_Pnt myPnt;
4624 gp_Dir myTgt;
4625 double myAngle;
4626 double myPrm;
4627 };
4628 */
4629
4630 //=======================================================================
4631 //function : ExtrusionAlongTrack
4632 //purpose  :
4633 //=======================================================================
4634 SMESH_MeshEditor::Extrusion_Error
4635 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4636                                        SMESH_subMesh*       theTrack,
4637                                        const SMDS_MeshNode* theN1,
4638                                        const bool           theHasAngles,
4639                                        list<double>&        theAngles,
4640                                        const bool           theLinearVariation,
4641                                        const bool           theHasRefPoint,
4642                                        const gp_Pnt&        theRefPoint,
4643                                        const bool           theMakeGroups)
4644 {
4645   MESSAGE("ExtrusionAlongTrack");
4646   myLastCreatedElems.Clear();
4647   myLastCreatedNodes.Clear();
4648
4649   int aNbE;
4650   std::list<double> aPrms;
4651   TIDSortedElemSet::iterator itElem;
4652
4653   gp_XYZ aGC;
4654   TopoDS_Edge aTrackEdge;
4655   TopoDS_Vertex aV1, aV2;
4656
4657   SMDS_ElemIteratorPtr aItE;
4658   SMDS_NodeIteratorPtr aItN;
4659   SMDSAbs_ElementType aTypeE;
4660
4661   TNodeOfNodeListMap mapNewNodes;
4662
4663   // 1. Check data
4664   aNbE = theElements.size();
4665   // nothing to do
4666   if ( !aNbE )
4667     return EXTR_NO_ELEMENTS;
4668
4669   // 1.1 Track Pattern
4670   ASSERT( theTrack );
4671
4672   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4673
4674   aItE = pSubMeshDS->GetElements();
4675   while ( aItE->more() ) {
4676     const SMDS_MeshElement* pE = aItE->next();
4677     aTypeE = pE->GetType();
4678     // Pattern must contain links only
4679     if ( aTypeE != SMDSAbs_Edge )
4680       return EXTR_PATH_NOT_EDGE;
4681   }
4682
4683   list<SMESH_MeshEditor_PathPoint> fullList;
4684
4685   const TopoDS_Shape& aS = theTrack->GetSubShape();
4686   // Sub shape for the Pattern must be an Edge or Wire
4687   if( aS.ShapeType() == TopAbs_EDGE ) {
4688     aTrackEdge = TopoDS::Edge( aS );
4689     // the Edge must not be degenerated
4690     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4691       return EXTR_BAD_PATH_SHAPE;
4692     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4693     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4694     const SMDS_MeshNode* aN1 = aItN->next();
4695     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4696     const SMDS_MeshNode* aN2 = aItN->next();
4697     // starting node must be aN1 or aN2
4698     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4699       return EXTR_BAD_STARTING_NODE;
4700     aItN = pSubMeshDS->GetNodes();
4701     while ( aItN->more() ) {
4702       const SMDS_MeshNode* pNode = aItN->next();
4703       const SMDS_EdgePosition* pEPos =
4704         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4705       double aT = pEPos->GetUParameter();
4706       aPrms.push_back( aT );
4707     }
4708     //Extrusion_Error err =
4709     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4710   } else if( aS.ShapeType() == TopAbs_WIRE ) {
4711     list< SMESH_subMesh* > LSM;
4712     TopTools_SequenceOfShape Edges;
4713     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4714     while(itSM->more()) {
4715       SMESH_subMesh* SM = itSM->next();
4716       LSM.push_back(SM);
4717       const TopoDS_Shape& aS = SM->GetSubShape();
4718       Edges.Append(aS);
4719     }
4720     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4721     int startNid = theN1->GetID();
4722     TColStd_MapOfInteger UsedNums;
4723     
4724     int NbEdges = Edges.Length();
4725     int i = 1;
4726     for(; i<=NbEdges; i++) {
4727       int k = 0;
4728       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4729       for(; itLSM!=LSM.end(); itLSM++) {
4730         k++;
4731         if(UsedNums.Contains(k)) continue;
4732         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4733         SMESH_subMesh* locTrack = *itLSM;
4734         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4735         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4736         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4737         const SMDS_MeshNode* aN1 = aItN->next();
4738         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4739         const SMDS_MeshNode* aN2 = aItN->next();
4740         // starting node must be aN1 or aN2
4741         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4742         // 2. Collect parameters on the track edge
4743         aPrms.clear();
4744         aItN = locMeshDS->GetNodes();
4745         while ( aItN->more() ) {
4746           const SMDS_MeshNode* pNode = aItN->next();
4747           const SMDS_EdgePosition* pEPos =
4748             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4749           double aT = pEPos->GetUParameter();
4750           aPrms.push_back( aT );
4751         }
4752         list<SMESH_MeshEditor_PathPoint> LPP;
4753         //Extrusion_Error err =
4754         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4755         LLPPs.push_back(LPP);
4756         UsedNums.Add(k);
4757         // update startN for search following egde
4758         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4759         else startNid = aN1->GetID();
4760         break;
4761       }
4762     }
4763     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4764     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4765     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4766     for(; itPP!=firstList.end(); itPP++) {
4767       fullList.push_back( *itPP );
4768     }
4769     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4770     fullList.pop_back();
4771     itLLPP++;
4772     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4773       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4774       itPP = currList.begin();
4775       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4776       gp_Dir D1 = PP1.Tangent();
4777       gp_Dir D2 = PP2.Tangent();
4778       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4779                            (D1.Z()+D2.Z())/2 ) );
4780       PP1.SetTangent(Dnew);
4781       fullList.push_back(PP1);
4782       itPP++;
4783       for(; itPP!=firstList.end(); itPP++) {
4784         fullList.push_back( *itPP );
4785       }
4786       PP1 = fullList.back();
4787       fullList.pop_back();
4788     }
4789     // if wire not closed
4790     fullList.push_back(PP1);
4791     // else ???
4792   }
4793   else {
4794     return EXTR_BAD_PATH_SHAPE;
4795   }
4796
4797   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4798                           theHasRefPoint, theRefPoint, theMakeGroups);
4799 }
4800
4801
4802 //=======================================================================
4803 //function : ExtrusionAlongTrack
4804 //purpose  :
4805 //=======================================================================
4806 SMESH_MeshEditor::Extrusion_Error
4807 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4808                                        SMESH_Mesh*          theTrack,
4809                                        const SMDS_MeshNode* theN1,
4810                                        const bool           theHasAngles,
4811                                        list<double>&        theAngles,
4812                                        const bool           theLinearVariation,
4813                                        const bool           theHasRefPoint,
4814                                        const gp_Pnt&        theRefPoint,
4815                                        const bool           theMakeGroups)
4816 {
4817   myLastCreatedElems.Clear();
4818   myLastCreatedNodes.Clear();
4819
4820   int aNbE;
4821   std::list<double> aPrms;
4822   TIDSortedElemSet::iterator itElem;
4823
4824   gp_XYZ aGC;
4825   TopoDS_Edge aTrackEdge;
4826   TopoDS_Vertex aV1, aV2;
4827
4828   SMDS_ElemIteratorPtr aItE;
4829   SMDS_NodeIteratorPtr aItN;
4830   SMDSAbs_ElementType aTypeE;
4831
4832   TNodeOfNodeListMap mapNewNodes;
4833
4834   // 1. Check data
4835   aNbE = theElements.size();
4836   // nothing to do
4837   if ( !aNbE )
4838     return EXTR_NO_ELEMENTS;
4839
4840   // 1.1 Track Pattern
4841   ASSERT( theTrack );
4842
4843   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4844
4845   aItE = pMeshDS->elementsIterator();
4846   while ( aItE->more() ) {
4847     const SMDS_MeshElement* pE = aItE->next();
4848     aTypeE = pE->GetType();
4849     // Pattern must contain links only
4850     if ( aTypeE != SMDSAbs_Edge )
4851       return EXTR_PATH_NOT_EDGE;
4852   }
4853
4854   list<SMESH_MeshEditor_PathPoint> fullList;
4855
4856   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4857
4858   if( aS == SMESH_Mesh::PseudoShape() ) {
4859     //Mesh without shape
4860     const SMDS_MeshNode* currentNode = NULL;
4861     const SMDS_MeshNode* prevNode = theN1;
4862     std::vector<const SMDS_MeshNode*> aNodesList;
4863     aNodesList.push_back(theN1);
4864     int nbEdges = 0, conn=0;
4865     const SMDS_MeshElement* prevElem = NULL;
4866     const SMDS_MeshElement* currentElem = NULL;
4867     int totalNbEdges = theTrack->NbEdges();
4868     SMDS_ElemIteratorPtr nIt;
4869     bool isClosed = false;
4870
4871     //check start node
4872     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
4873       return EXTR_BAD_STARTING_NODE;
4874     }
4875     
4876     conn = nbEdgeConnectivity(theN1);
4877     if(conn > 2)
4878       return EXTR_PATH_NOT_EDGE;
4879
4880     aItE = theN1->GetInverseElementIterator();
4881     prevElem = aItE->next();
4882     currentElem = prevElem;
4883     //Get all nodes
4884     if(totalNbEdges == 1 ) {
4885       nIt = currentElem->nodesIterator();
4886       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4887       if(currentNode == prevNode)
4888         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4889       aNodesList.push_back(currentNode);
4890     } else { 
4891       nIt = currentElem->nodesIterator();
4892       while( nIt->more() ) {
4893         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4894         if(currentNode == prevNode)
4895           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4896         aNodesList.push_back(currentNode);
4897         
4898         //case of the closed mesh
4899         if(currentNode == theN1) {
4900           nbEdges++;
4901           isClosed = true;
4902           break;
4903         }
4904
4905         conn = nbEdgeConnectivity(currentNode);
4906         if(conn > 2) {
4907           return EXTR_PATH_NOT_EDGE;    
4908         }else if( conn == 1 && nbEdges > 0 ) {
4909           //End of the path
4910           nbEdges++;
4911           break;
4912         }else {
4913           prevNode = currentNode;
4914           aItE = currentNode->GetInverseElementIterator();
4915           currentElem = aItE->next();
4916           if( currentElem  == prevElem)
4917             currentElem = aItE->next();
4918           nIt = currentElem->nodesIterator();
4919           prevElem = currentElem;
4920           nbEdges++;
4921         }
4922       }
4923     } 
4924     
4925     if(nbEdges != totalNbEdges)
4926       return EXTR_PATH_NOT_EDGE;
4927
4928     TopTools_SequenceOfShape Edges;
4929     double x1,x2,y1,y2,z1,z2;
4930     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4931     int startNid = theN1->GetID();
4932     for(int i = 1; i < aNodesList.size(); i++) {
4933       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
4934       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
4935       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
4936       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));  
4937       list<SMESH_MeshEditor_PathPoint> LPP;
4938       aPrms.clear();
4939       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
4940       LLPPs.push_back(LPP);
4941       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
4942       else startNid = aNodesList[i-1]->GetID();
4943
4944     }
4945
4946     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4947     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4948     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4949     for(; itPP!=firstList.end(); itPP++) {
4950       fullList.push_back( *itPP );
4951     }
4952
4953     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4954     SMESH_MeshEditor_PathPoint PP2;
4955     fullList.pop_back();
4956     itLLPP++;
4957     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4958       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4959       itPP = currList.begin();
4960       PP2 = currList.front();
4961       gp_Dir D1 = PP1.Tangent();
4962       gp_Dir D2 = PP2.Tangent();
4963       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4964                            (D1.Z()+D2.Z())/2 ) );
4965       PP1.SetTangent(Dnew);
4966       fullList.push_back(PP1);
4967       itPP++;
4968       for(; itPP!=currList.end(); itPP++) {
4969         fullList.push_back( *itPP );
4970       }
4971       PP1 = fullList.back();
4972       fullList.pop_back();
4973     }
4974     fullList.push_back(PP1);
4975     
4976   } // Sub shape for the Pattern must be an Edge or Wire
4977   else if( aS.ShapeType() == TopAbs_EDGE ) {
4978     aTrackEdge = TopoDS::Edge( aS );
4979     // the Edge must not be degenerated
4980     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4981       return EXTR_BAD_PATH_SHAPE;
4982     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4983     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4984     const SMDS_MeshNode* aN1 = aItN->next();
4985     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4986     const SMDS_MeshNode* aN2 = aItN->next();
4987     // starting node must be aN1 or aN2
4988     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4989       return EXTR_BAD_STARTING_NODE;
4990     aItN = pMeshDS->nodesIterator();
4991     while ( aItN->more() ) {
4992       const SMDS_MeshNode* pNode = aItN->next();
4993       if( pNode==aN1 || pNode==aN2 ) continue;
4994       const SMDS_EdgePosition* pEPos =
4995         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4996       double aT = pEPos->GetUParameter();
4997       aPrms.push_back( aT );
4998     }
4999     //Extrusion_Error err =
5000     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5001   }
5002   else if( aS.ShapeType() == TopAbs_WIRE ) {
5003     list< SMESH_subMesh* > LSM;
5004     TopTools_SequenceOfShape Edges;
5005     TopExp_Explorer eExp(aS, TopAbs_EDGE);
5006     for(; eExp.More(); eExp.Next()) {
5007       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5008       if( BRep_Tool::Degenerated(E) ) continue;
5009       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5010       if(SM) {
5011         LSM.push_back(SM);
5012         Edges.Append(E);
5013       }
5014     }
5015     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5016     int startNid = theN1->GetID();
5017     TColStd_MapOfInteger UsedNums;
5018     int NbEdges = Edges.Length();
5019     int i = 1;
5020     for(; i<=NbEdges; i++) {
5021       int k = 0;
5022       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5023       for(; itLSM!=LSM.end(); itLSM++) {
5024         k++;
5025         if(UsedNums.Contains(k)) continue;
5026         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5027         SMESH_subMesh* locTrack = *itLSM;
5028         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5029         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5030         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5031         const SMDS_MeshNode* aN1 = aItN->next();
5032         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5033         const SMDS_MeshNode* aN2 = aItN->next();
5034         // starting node must be aN1 or aN2
5035         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
5036         // 2. Collect parameters on the track edge
5037         aPrms.clear();
5038         aItN = locMeshDS->GetNodes();
5039         while ( aItN->more() ) {
5040           const SMDS_MeshNode* pNode = aItN->next();
5041           const SMDS_EdgePosition* pEPos =
5042             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5043           double aT = pEPos->GetUParameter();
5044           aPrms.push_back( aT );
5045         }
5046         list<SMESH_MeshEditor_PathPoint> LPP;
5047         //Extrusion_Error err =
5048         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
5049         LLPPs.push_back(LPP);
5050         UsedNums.Add(k);
5051         // update startN for search following egde
5052         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
5053         else startNid = aN1->GetID();
5054         break;
5055       }
5056     }
5057     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5058     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5059     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5060     for(; itPP!=firstList.end(); itPP++) {
5061       fullList.push_back( *itPP );
5062     }
5063     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5064     fullList.pop_back();
5065     itLLPP++;
5066     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5067       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5068       itPP = currList.begin();
5069       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5070       gp_Dir D1 = PP1.Tangent();
5071       gp_Dir D2 = PP2.Tangent();
5072       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5073                            (D1.Z()+D2.Z())/2 ) );
5074       PP1.SetTangent(Dnew);
5075       fullList.push_back(PP1);
5076       itPP++;
5077       for(; itPP!=currList.end(); itPP++) {
5078         fullList.push_back( *itPP );
5079       }
5080       PP1 = fullList.back();
5081       fullList.pop_back();
5082     }
5083     // if wire not closed
5084     fullList.push_back(PP1);
5085     // else ???
5086   }
5087   else {
5088     return EXTR_BAD_PATH_SHAPE;
5089   }
5090
5091   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5092                           theHasRefPoint, theRefPoint, theMakeGroups);
5093 }
5094
5095
5096 //=======================================================================
5097 //function : MakeEdgePathPoints
5098 //purpose  : auxilary for ExtrusionAlongTrack
5099 //=======================================================================
5100 SMESH_MeshEditor::Extrusion_Error
5101 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5102                                      const TopoDS_Edge& aTrackEdge,
5103                                      bool FirstIsStart,
5104                                      list<SMESH_MeshEditor_PathPoint>& LPP)
5105 {
5106   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5107   aTolVec=1.e-7;
5108   aTolVec2=aTolVec*aTolVec;
5109   double aT1, aT2;
5110   TopoDS_Vertex aV1, aV2;
5111   TopExp::Vertices( aTrackEdge, aV1, aV2 );
5112   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5113   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5114   // 2. Collect parameters on the track edge
5115   aPrms.push_front( aT1 );
5116   aPrms.push_back( aT2 );
5117   // sort parameters
5118   aPrms.sort();
5119   if( FirstIsStart ) {
5120     if ( aT1 > aT2 ) {
5121       aPrms.reverse();
5122     }
5123   }
5124   else {
5125     if ( aT2 > aT1 ) {
5126       aPrms.reverse();
5127     }
5128   }
5129   // 3. Path Points
5130   SMESH_MeshEditor_PathPoint aPP;
5131   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5132   std::list<double>::iterator aItD = aPrms.begin();
5133   for(; aItD != aPrms.end(); ++aItD) {
5134     double aT = *aItD;
5135     gp_Pnt aP3D;
5136     gp_Vec aVec;
5137     aC3D->D1( aT, aP3D, aVec );
5138     aL2 = aVec.SquareMagnitude();
5139     if ( aL2 < aTolVec2 )
5140       return EXTR_CANT_GET_TANGENT;
5141     gp_Dir aTgt( aVec );
5142     aPP.SetPnt( aP3D );
5143     aPP.SetTangent( aTgt );
5144     aPP.SetParameter( aT );
5145     LPP.push_back(aPP);
5146   }
5147   return EXTR_OK;
5148 }
5149
5150
5151 //=======================================================================
5152 //function : MakeExtrElements
5153 //purpose  : auxilary for ExtrusionAlongTrack
5154 //=======================================================================
5155 SMESH_MeshEditor::Extrusion_Error
5156 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5157                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5158                                    const bool theHasAngles,
5159                                    list<double>& theAngles,
5160                                    const bool theLinearVariation,
5161                                    const bool theHasRefPoint,
5162                                    const gp_Pnt& theRefPoint,
5163                                    const bool theMakeGroups)
5164 {
5165   MESSAGE("MakeExtrElements");
5166   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5167   int aNbTP = fullList.size();
5168   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5169   // Angles
5170   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5171     LinearAngleVariation(aNbTP-1, theAngles);
5172   }
5173   vector<double> aAngles( aNbTP );
5174   int j = 0;
5175   for(; j<aNbTP; ++j) {
5176     aAngles[j] = 0.;
5177   }
5178   if ( theHasAngles ) {
5179     double anAngle;;
5180     std::list<double>::iterator aItD = theAngles.begin();
5181     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5182       anAngle = *aItD;
5183       aAngles[j] = anAngle;
5184     }
5185   }
5186   // fill vector of path points with angles
5187   //aPPs.resize(fullList.size());
5188   j = -1;
5189   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5190   for(; itPP!=fullList.end(); itPP++) {
5191     j++;
5192     SMESH_MeshEditor_PathPoint PP = *itPP;
5193     PP.SetAngle(aAngles[j]);
5194     aPPs[j] = PP;
5195   }
5196
5197   TNodeOfNodeListMap mapNewNodes;
5198   TElemOfVecOfNnlmiMap mapElemNewNodes;
5199   TElemOfElemListMap newElemsMap;
5200   TIDSortedElemSet::iterator itElem;
5201   double aX, aY, aZ;
5202   int aNb;
5203   SMDSAbs_ElementType aTypeE;
5204   // source elements for each generated one
5205   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5206
5207   // 3. Center of rotation aV0
5208   gp_Pnt aV0 = theRefPoint;
5209   gp_XYZ aGC;
5210   if ( !theHasRefPoint ) {
5211     aNb = 0;
5212     aGC.SetCoord( 0.,0.,0. );
5213
5214     itElem = theElements.begin();
5215     for ( ; itElem != theElements.end(); itElem++ ) {
5216       const SMDS_MeshElement* elem = *itElem;
5217
5218       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5219       while ( itN->more() ) {
5220         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5221         aX = node->X();
5222         aY = node->Y();
5223         aZ = node->Z();
5224
5225         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5226           list<const SMDS_MeshNode*> aLNx;
5227           mapNewNodes[node] = aLNx;
5228           //
5229           gp_XYZ aXYZ( aX, aY, aZ );
5230           aGC += aXYZ;
5231           ++aNb;
5232         }
5233       }
5234     }
5235     aGC /= aNb;
5236     aV0.SetXYZ( aGC );
5237   } // if (!theHasRefPoint) {
5238   mapNewNodes.clear();
5239
5240   // 4. Processing the elements
5241   SMESHDS_Mesh* aMesh = GetMeshDS();
5242
5243   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5244     // check element type
5245     const SMDS_MeshElement* elem = *itElem;
5246     aTypeE = elem->GetType();
5247     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5248       continue;
5249
5250     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5251     newNodesItVec.reserve( elem->NbNodes() );
5252
5253     // loop on elem nodes
5254     int nodeIndex = -1;
5255     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5256     while ( itN->more() )
5257     {
5258       ++nodeIndex;
5259       // check if a node has been already processed
5260       const SMDS_MeshNode* node =
5261         static_cast<const SMDS_MeshNode*>( itN->next() );
5262       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5263       if ( nIt == mapNewNodes.end() ) {
5264         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5265         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5266
5267         // make new nodes
5268         aX = node->X();  aY = node->Y(); aZ = node->Z();
5269
5270         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5271         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5272         gp_Ax1 anAx1, anAxT1T0;
5273         gp_Dir aDT1x, aDT0x, aDT1T0;
5274
5275         aTolAng=1.e-4;
5276
5277         aV0x = aV0;
5278         aPN0.SetCoord(aX, aY, aZ);
5279
5280         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5281         aP0x = aPP0.Pnt();
5282         aDT0x= aPP0.Tangent();
5283         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5284
5285         for ( j = 1; j < aNbTP; ++j ) {
5286           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5287           aP1x = aPP1.Pnt();
5288           aDT1x = aPP1.Tangent();
5289           aAngle1x = aPP1.Angle();
5290
5291           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5292           // Translation
5293           gp_Vec aV01x( aP0x, aP1x );
5294           aTrsf.SetTranslation( aV01x );
5295
5296           // traslated point
5297           aV1x = aV0x.Transformed( aTrsf );
5298           aPN1 = aPN0.Transformed( aTrsf );
5299
5300           // rotation 1 [ T1,T0 ]
5301           aAngleT1T0=-aDT1x.Angle( aDT0x );
5302           if (fabs(aAngleT1T0) > aTolAng) {
5303             aDT1T0=aDT1x^aDT0x;
5304             anAxT1T0.SetLocation( aV1x );
5305             anAxT1T0.SetDirection( aDT1T0 );
5306             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5307
5308             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5309           }
5310
5311           // rotation 2
5312           if ( theHasAngles ) {
5313             anAx1.SetLocation( aV1x );
5314             anAx1.SetDirection( aDT1x );
5315             aTrsfRot.SetRotation( anAx1, aAngle1x );
5316
5317             aPN1 = aPN1.Transformed( aTrsfRot );
5318           }
5319
5320           // make new node
5321           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5322           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5323             // create additional node
5324             double x = ( aPN1.X() + aPN0.X() )/2.;
5325             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5326             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5327             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5328             myLastCreatedNodes.Append(newNode);
5329             srcNodes.Append( node );
5330             listNewNodes.push_back( newNode );
5331           }
5332           aX = aPN1.X();
5333           aY = aPN1.Y();
5334           aZ = aPN1.Z();
5335           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5336           myLastCreatedNodes.Append(newNode);
5337           srcNodes.Append( node );
5338           listNewNodes.push_back( newNode );
5339
5340           aPN0 = aPN1;
5341           aP0x = aP1x;
5342           aV0x = aV1x;
5343           aDT0x = aDT1x;
5344         }
5345       }
5346
5347       else {
5348         // if current elem is quadratic and current node is not medium
5349         // we have to check - may be it is needed to insert additional nodes
5350         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5351           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5352           if(listNewNodes.size()==aNbTP-1) {
5353             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5354             gp_XYZ P(node->X(), node->Y(), node->Z());
5355             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5356             int i;
5357             for(i=0; i<aNbTP-1; i++) {
5358               const SMDS_MeshNode* N = *it;
5359               double x = ( N->X() + P.X() )/2.;
5360               double y = ( N->Y() + P.Y() )/2.;
5361               double z = ( N->Z() + P.Z() )/2.;
5362               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5363               srcNodes.Append( node );
5364               myLastCreatedNodes.Append(newN);
5365               aNodes[2*i] = newN;
5366               aNodes[2*i+1] = N;
5367               P = gp_XYZ(N->X(),N->Y(),N->Z());
5368             }
5369             listNewNodes.clear();
5370             for(i=0; i<2*(aNbTP-1); i++) {
5371               listNewNodes.push_back(aNodes[i]);
5372             }
5373           }
5374         }
5375       }
5376
5377       newNodesItVec.push_back( nIt );
5378     }
5379     // make new elements
5380     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5381     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5382     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5383   }
5384
5385   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5386
5387   if ( theMakeGroups )
5388     generateGroups( srcNodes, srcElems, "extruded");
5389
5390   return EXTR_OK;
5391 }
5392
5393
5394 //=======================================================================
5395 //function : LinearAngleVariation
5396 //purpose  : auxilary for ExtrusionAlongTrack
5397 //=======================================================================
5398 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5399                                             list<double>& Angles)
5400 {
5401   int nbAngles = Angles.size();
5402   if( nbSteps > nbAngles ) {
5403     vector<double> theAngles(nbAngles);
5404     list<double>::iterator it = Angles.begin();
5405     int i = -1;
5406     for(; it!=Angles.end(); it++) {
5407       i++;
5408       theAngles[i] = (*it);
5409     }
5410     list<double> res;
5411     double rAn2St = double( nbAngles ) / double( nbSteps );
5412     double angPrev = 0, angle;
5413     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5414       double angCur = rAn2St * ( iSt+1 );
5415       double angCurFloor  = floor( angCur );
5416       double angPrevFloor = floor( angPrev );
5417       if ( angPrevFloor == angCurFloor )
5418         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5419       else {
5420         int iP = int( angPrevFloor );
5421         double angPrevCeil = ceil(angPrev);
5422         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5423
5424         int iC = int( angCurFloor );
5425         if ( iC < nbAngles )
5426           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5427
5428         iP = int( angPrevCeil );
5429         while ( iC-- > iP )
5430           angle += theAngles[ iC ];
5431       }
5432       res.push_back(angle);
5433       angPrev = angCur;
5434     }
5435     Angles.clear();
5436     it = res.begin();
5437     for(; it!=res.end(); it++)
5438       Angles.push_back( *it );
5439   }
5440 }
5441
5442
5443 //================================================================================
5444 /*!
5445  * \brief Move or copy theElements applying theTrsf to their nodes
5446  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5447  *  \param theTrsf - transformation to apply
5448  *  \param theCopy - if true, create translated copies of theElems
5449  *  \param theMakeGroups - if true and theCopy, create translated groups
5450  *  \param theTargetMesh - mesh to copy translated elements into
5451  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5452  */
5453 //================================================================================
5454
5455 SMESH_MeshEditor::PGroupIDs
5456 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5457                              const gp_Trsf&     theTrsf,
5458                              const bool         theCopy,
5459                              const bool         theMakeGroups,
5460                              SMESH_Mesh*        theTargetMesh)
5461 {
5462   myLastCreatedElems.Clear();
5463   myLastCreatedNodes.Clear();
5464
5465   bool needReverse = false;
5466   string groupPostfix;
5467   switch ( theTrsf.Form() ) {
5468   case gp_PntMirror:
5469     MESSAGE("gp_PntMirror");
5470     needReverse = true;
5471     groupPostfix = "mirrored";
5472     break;
5473   case gp_Ax1Mirror:
5474     MESSAGE("gp_Ax1Mirror");
5475     groupPostfix = "mirrored";
5476     break;
5477   case gp_Ax2Mirror:
5478     MESSAGE("gp_Ax2Mirror");
5479     needReverse = true;
5480     groupPostfix = "mirrored";
5481     break;
5482   case gp_Rotation:
5483     MESSAGE("gp_Rotation");
5484     groupPostfix = "rotated";
5485     break;
5486   case gp_Translation:
5487     MESSAGE("gp_Translation");
5488     groupPostfix = "translated";
5489     break;
5490   case gp_Scale:
5491     MESSAGE("gp_Scale");
5492     groupPostfix = "scaled";
5493     break;
5494   case gp_CompoundTrsf: // different scale by axis
5495     MESSAGE("gp_CompoundTrsf");
5496     groupPostfix = "scaled";
5497     break;
5498   default:
5499     MESSAGE("default");
5500     needReverse = false;
5501     groupPostfix = "transformed";
5502   }
5503
5504   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5505   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5506   SMESHDS_Mesh* aMesh    = GetMeshDS();
5507
5508
5509   // map old node to new one
5510   TNodeNodeMap nodeMap;
5511
5512   // elements sharing moved nodes; those of them which have all
5513   // nodes mirrored but are not in theElems are to be reversed
5514   TIDSortedElemSet inverseElemSet;
5515
5516   // source elements for each generated one
5517   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5518
5519   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5520   TIDSortedElemSet orphanNode;
5521
5522   if ( theElems.empty() ) // transform the whole mesh
5523   {
5524     // add all elements
5525     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5526     while ( eIt->more() ) theElems.insert( eIt->next() );
5527     // add orphan nodes
5528     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5529     while ( nIt->more() )
5530     {
5531       const SMDS_MeshNode* node = nIt->next();
5532       if ( node->NbInverseElements() == 0)
5533         orphanNode.insert( node );
5534     }
5535   }
5536
5537   // loop on elements to transform nodes : first orphan nodes then elems
5538   TIDSortedElemSet::iterator itElem;
5539   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5540   for (int i=0; i<2; i++)
5541   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5542     const SMDS_MeshElement* elem = *itElem;
5543     if ( !elem )
5544       continue;
5545
5546     // loop on elem nodes
5547     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5548     while ( itN->more() ) {
5549
5550       const SMDS_MeshNode* node = cast2Node( itN->next() );
5551       // check if a node has been already transformed
5552       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5553         nodeMap.insert( make_pair ( node, node ));
5554       if ( !n2n_isnew.second )
5555         continue;
5556
5557       double coord[3];
5558       coord[0] = node->X();
5559       coord[1] = node->Y();
5560       coord[2] = node->Z();
5561       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5562       if ( theTargetMesh ) {
5563         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5564         n2n_isnew.first->second = newNode;
5565         myLastCreatedNodes.Append(newNode);
5566         srcNodes.Append( node );
5567       }
5568       else if ( theCopy ) {
5569         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5570         n2n_isnew.first->second = newNode;
5571         myLastCreatedNodes.Append(newNode);
5572         srcNodes.Append( node );
5573       }
5574       else {
5575         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5576         // node position on shape becomes invalid
5577         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5578           ( SMDS_SpacePosition::originSpacePosition() );
5579       }
5580
5581       // keep inverse elements
5582       if ( !theCopy && !theTargetMesh && needReverse ) {
5583         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5584         while ( invElemIt->more() ) {
5585           const SMDS_MeshElement* iel = invElemIt->next();
5586           inverseElemSet.insert( iel );
5587         }
5588       }
5589     }
5590   }
5591
5592   // either create new elements or reverse mirrored ones
5593   if ( !theCopy && !needReverse && !theTargetMesh )
5594     return PGroupIDs();
5595
5596   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5597   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5598     theElems.insert( *invElemIt );
5599
5600   // replicate or reverse elements
5601   // TODO revoir ordre reverse vtk
5602   enum {
5603     REV_TETRA   = 0,  //  = nbNodes - 4
5604     REV_PYRAMID = 1,  //  = nbNodes - 4
5605     REV_PENTA   = 2,  //  = nbNodes - 4
5606     REV_FACE    = 3,
5607     REV_HEXA    = 4,  //  = nbNodes - 4
5608     FORWARD     = 5
5609   };
5610   int index[][8] = {
5611     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5612     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5613     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5614     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5615     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5616     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5617   };
5618
5619   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5620   {
5621     const SMDS_MeshElement* elem = *itElem;
5622     if ( !elem || elem->GetType() == SMDSAbs_Node )
5623       continue;
5624
5625     int nbNodes = elem->NbNodes();
5626     int elemType = elem->GetType();
5627
5628     if (elem->IsPoly()) {
5629       // Polygon or Polyhedral Volume
5630       switch ( elemType ) {
5631       case SMDSAbs_Face:
5632         {
5633           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5634           int iNode = 0;
5635           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5636           while (itN->more()) {
5637             const SMDS_MeshNode* node =
5638               static_cast<const SMDS_MeshNode*>(itN->next());
5639             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5640             if (nodeMapIt == nodeMap.end())
5641               break; // not all nodes transformed
5642             if (needReverse) {
5643               // reverse mirrored faces and volumes
5644               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5645             } else {
5646               poly_nodes[iNode] = (*nodeMapIt).second;
5647             }
5648             iNode++;
5649           }
5650           if ( iNode != nbNodes )
5651             continue; // not all nodes transformed
5652
5653           if ( theTargetMesh ) {
5654             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5655             srcElems.Append( elem );
5656           }
5657           else if ( theCopy ) {
5658             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5659             srcElems.Append( elem );
5660           }
5661           else {
5662             aMesh->ChangePolygonNodes(elem, poly_nodes);
5663           }
5664         }
5665         break;
5666       case SMDSAbs_Volume:
5667         {
5668           // ATTENTION: Reversing is not yet done!!!
5669           const SMDS_VtkVolume* aPolyedre =
5670             dynamic_cast<const SMDS_VtkVolume*>( elem );
5671           if (!aPolyedre) {
5672             MESSAGE("Warning: bad volumic element");
5673             continue;
5674           }
5675
5676           vector<const SMDS_MeshNode*> poly_nodes;
5677           vector<int> quantities;
5678
5679           bool allTransformed = true;
5680           int nbFaces = aPolyedre->NbFaces();
5681           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5682             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5683             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5684               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5685               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5686               if (nodeMapIt == nodeMap.end()) {
5687                 allTransformed = false; // not all nodes transformed
5688               } else {
5689                 poly_nodes.push_back((*nodeMapIt).second);
5690               }
5691             }
5692             quantities.push_back(nbFaceNodes);
5693           }
5694           if ( !allTransformed )
5695             continue; // not all nodes transformed
5696
5697           if ( theTargetMesh ) {
5698             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5699             srcElems.Append( elem );
5700           }
5701           else if ( theCopy ) {
5702             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5703             srcElems.Append( elem );
5704           }
5705           else {
5706             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5707           }
5708         }
5709         break;
5710       default:;
5711       }
5712       continue;
5713     }
5714
5715     // Regular elements
5716     int* i = index[ FORWARD ];
5717     if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5718       if ( elemType == SMDSAbs_Face )
5719         i = index[ REV_FACE ];
5720       else
5721         i = index[ nbNodes - 4 ];
5722     }
5723     if(elem->IsQuadratic()) {
5724       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5725       i = anIds;
5726       if(needReverse) {
5727         if(nbNodes==3) { // quadratic edge
5728           static int anIds[] = {1,0,2};
5729           i = anIds;
5730         }
5731         else if(nbNodes==6) { // quadratic triangle
5732           static int anIds[] = {0,2,1,5,4,3};
5733           i = anIds;
5734         }
5735         else if(nbNodes==8) { // quadratic quadrangle
5736           static int anIds[] = {0,3,2,1,7,6,5,4};
5737           i = anIds;
5738         }
5739         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5740           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5741           i = anIds;
5742         }
5743         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5744           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5745           i = anIds;
5746         }
5747         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5748           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5749           i = anIds;
5750         }
5751         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5752           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5753           i = anIds;
5754         }
5755       }
5756     }
5757
5758     // find transformed nodes
5759     vector<const SMDS_MeshNode*> nodes(nbNodes);
5760     int iNode = 0;
5761     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5762     while ( itN->more() ) {
5763       const SMDS_MeshNode* node =
5764         static_cast<const SMDS_MeshNode*>( itN->next() );
5765       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5766       if ( nodeMapIt == nodeMap.end() )
5767         break; // not all nodes transformed
5768       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5769     }
5770     if ( iNode != nbNodes )
5771       continue; // not all nodes transformed
5772
5773     if ( theTargetMesh ) {
5774       if ( SMDS_MeshElement* copy =
5775            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5776         myLastCreatedElems.Append( copy );
5777         srcElems.Append( elem );
5778       }
5779     }
5780     else if ( theCopy ) {
5781       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5782         srcElems.Append( elem );
5783     }
5784     else {
5785       // reverse element as it was reversed by transformation
5786       if ( nbNodes > 2 )
5787         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5788     }
5789   }
5790
5791   PGroupIDs newGroupIDs;
5792
5793   if ( ( theMakeGroups && theCopy ) ||
5794        ( theMakeGroups && theTargetMesh ) )
5795     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5796
5797   return newGroupIDs;
5798 }
5799
5800
5801 ////=======================================================================
5802 ////function : Scale
5803 ////purpose  :
5804 ////=======================================================================
5805 //
5806 //SMESH_MeshEditor::PGroupIDs
5807 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5808 //                         const gp_Pnt&            thePoint,
5809 //                         const std::list<double>& theScaleFact,
5810 //                         const bool         theCopy,
5811 //                         const bool         theMakeGroups,
5812 //                         SMESH_Mesh*        theTargetMesh)
5813 //{
5814 //  MESSAGE("Scale");
5815 //  myLastCreatedElems.Clear();
5816 //  myLastCreatedNodes.Clear();
5817 //
5818 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5819 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5820 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
5821 //
5822 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5823 //  std::list<double>::const_iterator itS = theScaleFact.begin();
5824 //  scaleX = (*itS);
5825 //  if(theScaleFact.size()==1) {
5826 //    scaleY = (*itS);
5827 //    scaleZ= (*itS);
5828 //  }
5829 //  if(theScaleFact.size()==2) {
5830 //    itS++;
5831 //    scaleY = (*itS);
5832 //    scaleZ= (*itS);
5833 //  }
5834 //  if(theScaleFact.size()>2) {
5835 //    itS++;
5836 //    scaleY = (*itS);
5837 //    itS++;
5838 //    scaleZ= (*itS);
5839 //  }
5840 //
5841 //  // map old node to new one
5842 //  TNodeNodeMap nodeMap;
5843 //
5844 //  // elements sharing moved nodes; those of them which have all
5845 //  // nodes mirrored but are not in theElems are to be reversed
5846 //  TIDSortedElemSet inverseElemSet;
5847 //
5848 //  // source elements for each generated one
5849 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
5850 //
5851 //  // loop on theElems
5852 //  TIDSortedElemSet::iterator itElem;
5853 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5854 //    const SMDS_MeshElement* elem = *itElem;
5855 //    if ( !elem )
5856 //      continue;
5857 //
5858 //    // loop on elem nodes
5859 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5860 //    while ( itN->more() ) {
5861 //
5862 //      // check if a node has been already transformed
5863 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
5864 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5865 //        nodeMap.insert( make_pair ( node, node ));
5866 //      if ( !n2n_isnew.second )
5867 //        continue;
5868 //
5869 //      //double coord[3];
5870 //      //coord[0] = node->X();
5871 //      //coord[1] = node->Y();
5872 //      //coord[2] = node->Z();
5873 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5874 //      double dx = (node->X() - thePoint.X()) * scaleX;
5875 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
5876 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
5877 //      if ( theTargetMesh ) {
5878 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5879 //        const SMDS_MeshNode * newNode =
5880 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5881 //        n2n_isnew.first->second = newNode;
5882 //        myLastCreatedNodes.Append(newNode);
5883 //        srcNodes.Append( node );
5884 //      }
5885 //      else if ( theCopy ) {
5886 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5887 //        const SMDS_MeshNode * newNode =
5888 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5889 //        n2n_isnew.first->second = newNode;
5890 //        myLastCreatedNodes.Append(newNode);
5891 //        srcNodes.Append( node );
5892 //      }
5893 //      else {
5894 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5895 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5896 //        // node position on shape becomes invalid
5897 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
5898 //          ( SMDS_SpacePosition::originSpacePosition() );
5899 //      }
5900 //
5901 //      // keep inverse elements
5902 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
5903 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5904 //      //  while ( invElemIt->more() ) {
5905 //      //    const SMDS_MeshElement* iel = invElemIt->next();
5906 //      //    inverseElemSet.insert( iel );
5907 //      //  }
5908 //      //}
5909 //    }
5910 //  }
5911 //
5912 //  // either create new elements or reverse mirrored ones
5913 //  //if ( !theCopy && !needReverse && !theTargetMesh )
5914 //  if ( !theCopy && !theTargetMesh )
5915 //    return PGroupIDs();
5916 //
5917 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5918 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5919 //    theElems.insert( *invElemIt );
5920 //
5921 //  // replicate or reverse elements
5922 //
5923 //  enum {
5924 //    REV_TETRA   = 0,  //  = nbNodes - 4
5925 //    REV_PYRAMID = 1,  //  = nbNodes - 4
5926 //    REV_PENTA   = 2,  //  = nbNodes - 4
5927 //    REV_FACE    = 3,
5928 //    REV_HEXA    = 4,  //  = nbNodes - 4
5929 //    FORWARD     = 5
5930 //  };
5931 //  int index[][8] = {
5932 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5933 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5934 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5935 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5936 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5937 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5938 //  };
5939 //
5940 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5941 //  {
5942 //    const SMDS_MeshElement* elem = *itElem;
5943 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
5944 //      continue;
5945 //
5946 //    int nbNodes = elem->NbNodes();
5947 //    int elemType = elem->GetType();
5948 //
5949 //    if (elem->IsPoly()) {
5950 //      // Polygon or Polyhedral Volume
5951 //      switch ( elemType ) {
5952 //      case SMDSAbs_Face:
5953 //        {
5954 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5955 //          int iNode = 0;
5956 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5957 //          while (itN->more()) {
5958 //            const SMDS_MeshNode* node =
5959 //              static_cast<const SMDS_MeshNode*>(itN->next());
5960 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5961 //            if (nodeMapIt == nodeMap.end())
5962 //              break; // not all nodes transformed
5963 //            //if (needReverse) {
5964 //            //  // reverse mirrored faces and volumes
5965 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5966 //            //} else {
5967 //            poly_nodes[iNode] = (*nodeMapIt).second;
5968 //            //}
5969 //            iNode++;
5970 //          }
5971 //          if ( iNode != nbNodes )
5972 //            continue; // not all nodes transformed
5973 //
5974 //          if ( theTargetMesh ) {
5975 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5976 //            srcElems.Append( elem );
5977 //          }
5978 //          else if ( theCopy ) {
5979 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5980 //            srcElems.Append( elem );
5981 //          }
5982 //          else {
5983 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
5984 //          }
5985 //        }
5986 //        break;
5987 //      case SMDSAbs_Volume:
5988 //        {
5989 //          // ATTENTION: Reversing is not yet done!!!
5990 //          const SMDS_VtkVolume* aPolyedre =
5991 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
5992 //          if (!aPolyedre) {
5993 //            MESSAGE("Warning: bad volumic element");
5994 //            continue;
5995 //          }
5996 //
5997 //          vector<const SMDS_MeshNode*> poly_nodes;
5998 //          vector<int> quantities;
5999 //
6000 //          bool allTransformed = true;
6001 //          int nbFaces = aPolyedre->NbFaces();
6002 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
6003 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6004 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
6005 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
6006 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
6007 //              if (nodeMapIt == nodeMap.end()) {
6008 //                allTransformed = false; // not all nodes transformed
6009 //              } else {
6010 //                poly_nodes.push_back((*nodeMapIt).second);
6011 //              }
6012 //            }
6013 //            quantities.push_back(nbFaceNodes);
6014 //          }
6015 //          if ( !allTransformed )
6016 //            continue; // not all nodes transformed
6017 //
6018 //          if ( theTargetMesh ) {
6019 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
6020 //            srcElems.Append( elem );
6021 //          }
6022 //          else if ( theCopy ) {
6023 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
6024 //            srcElems.Append( elem );
6025 //          }
6026 //          else {
6027 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6028 //          }
6029 //        }
6030 //        break;
6031 //      default:;
6032 //      }
6033 //      continue;
6034 //    }
6035 //
6036 //    // Regular elements
6037 //    int* i = index[ FORWARD ];
6038 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
6039 //    //  if ( elemType == SMDSAbs_Face )
6040 //    //    i = index[ REV_FACE ];
6041 //    //  else
6042 //    //    i = index[ nbNodes - 4 ];
6043 //
6044 //    if(elem->IsQuadratic()) {
6045 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
6046 //      i = anIds;
6047 //      //if(needReverse) {
6048 //      //  if(nbNodes==3) { // quadratic edge
6049 //      //    static int anIds[] = {1,0,2};
6050 //      //    i = anIds;
6051 //      //  }
6052 //      //  else if(nbNodes==6) { // quadratic triangle
6053 //      //    static int anIds[] = {0,2,1,5,4,3};
6054 //      //    i = anIds;
6055 //      //  }
6056 //      //  else if(nbNodes==8) { // quadratic quadrangle
6057 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
6058 //      //    i = anIds;
6059 //      //  }
6060 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
6061 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
6062 //      //    i = anIds;
6063 //      //  }
6064 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
6065 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
6066 //      //    i = anIds;
6067 //      //  }
6068 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
6069 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
6070 //      //    i = anIds;
6071 //      //  }
6072 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
6073 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
6074 //      //    i = anIds;
6075 //      //  }
6076 //      //}
6077 //    }
6078 //
6079 //    // find transformed nodes
6080 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
6081 //    int iNode = 0;
6082 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6083 //    while ( itN->more() ) {
6084 //      const SMDS_MeshNode* node =
6085 //        static_cast<const SMDS_MeshNode*>( itN->next() );
6086 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
6087 //      if ( nodeMapIt == nodeMap.end() )
6088 //        break; // not all nodes transformed
6089 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
6090 //    }
6091 //    if ( iNode != nbNodes )
6092 //      continue; // not all nodes transformed
6093 //
6094 //    if ( theTargetMesh ) {
6095 //      if ( SMDS_MeshElement* copy =
6096 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
6097 //        myLastCreatedElems.Append( copy );
6098 //        srcElems.Append( elem );
6099 //      }
6100 //    }
6101 //    else if ( theCopy ) {
6102 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
6103 //        myLastCreatedElems.Append( copy );
6104 //        srcElems.Append( elem );
6105 //      }
6106 //    }
6107 //    else {
6108 //      // reverse element as it was reversed by transformation
6109 //      if ( nbNodes > 2 )
6110 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
6111 //    }
6112 //  }
6113 //
6114 //  PGroupIDs newGroupIDs;
6115 //
6116 //  if ( theMakeGroups && theCopy ||
6117 //       theMakeGroups && theTargetMesh ) {
6118 //    string groupPostfix = "scaled";
6119 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
6120 //  }
6121 //
6122 //  return newGroupIDs;
6123 //}
6124
6125
6126 //=======================================================================
6127 /*!
6128  * \brief Create groups of elements made during transformation
6129  * \param nodeGens - nodes making corresponding myLastCreatedNodes
6130  * \param elemGens - elements making corresponding myLastCreatedElems
6131  * \param postfix - to append to names of new groups
6132  */
6133 //=======================================================================
6134
6135 SMESH_MeshEditor::PGroupIDs
6136 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
6137                                  const SMESH_SequenceOfElemPtr& elemGens,
6138                                  const std::string&             postfix,
6139                                  SMESH_Mesh*                    targetMesh)
6140 {
6141   PGroupIDs newGroupIDs( new list<int> );
6142   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6143
6144   // Sort existing groups by types and collect their names
6145
6146   // to store an old group and a generated new one
6147   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6148   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6149   // group names
6150   set< string > groupNames;
6151   //
6152   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6153   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6154   while ( groupIt->more() ) {
6155     SMESH_Group * group = groupIt->next();
6156     if ( !group ) continue;
6157     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6158     if ( !groupDS || groupDS->IsEmpty() ) continue;
6159     groupNames.insert( group->GetName() );
6160     groupDS->SetStoreName( group->GetName() );
6161     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6162   }
6163
6164   // Groups creation
6165
6166   // loop on nodes and elements
6167   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6168   {
6169     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6170     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6171     if ( gens.Length() != elems.Length() )
6172       throw SALOME_Exception(LOCALIZED("invalid args"));
6173
6174     // loop on created elements
6175     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6176     {
6177       const SMDS_MeshElement* sourceElem = gens( iElem );
6178       if ( !sourceElem ) {
6179         MESSAGE("generateGroups(): NULL source element");
6180         continue;
6181       }
6182       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6183       if ( groupsOldNew.empty() ) {
6184         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6185           ++iElem; // skip all elements made by sourceElem
6186         continue;
6187       }
6188       // collect all elements made by sourceElem
6189       list< const SMDS_MeshElement* > resultElems;
6190       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6191         if ( resElem != sourceElem )
6192           resultElems.push_back( resElem );
6193       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6194         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6195           if ( resElem != sourceElem )
6196             resultElems.push_back( resElem );
6197       // do not generate element groups from node ones
6198       if ( sourceElem->GetType() == SMDSAbs_Node &&
6199            elems( iElem )->GetType() != SMDSAbs_Node )
6200         continue;
6201
6202       // add resultElems to groups made by ones the sourceElem belongs to
6203       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6204       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6205       {
6206         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6207         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6208         {
6209           SMDS_MeshGroup* & newGroup = gOldNew->second;
6210           if ( !newGroup )// create a new group
6211           {
6212             // make a name
6213             string name = oldGroup->GetStoreName();
6214             if ( !targetMesh ) {
6215               name += "_";
6216               name += postfix;
6217               int nb = 0;
6218               while ( !groupNames.insert( name ).second ) // name exists
6219               {
6220                 if ( nb == 0 ) {
6221                   name += "_1";
6222                 }
6223                 else {
6224                   TCollection_AsciiString nbStr(nb+1);
6225                   name.resize( name.rfind('_')+1 );
6226                   name += nbStr.ToCString();
6227                 }
6228                 ++nb;
6229               }
6230             }
6231             // make a group
6232             int id;
6233             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6234                                                  name.c_str(), id );
6235             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6236             newGroup = & groupDS->SMDSGroup();
6237             newGroupIDs->push_back( id );
6238           }
6239
6240           // fill in a new group
6241           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6242           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6243             newGroup->Add( *resElemIt );
6244         }
6245       }
6246     } // loop on created elements
6247   }// loop on nodes and elements
6248
6249   return newGroupIDs;
6250 }
6251
6252 //================================================================================
6253 /*!
6254  * \brief Return list of group of nodes close to each other within theTolerance
6255  *        Search among theNodes or in the whole mesh if theNodes is empty using
6256  *        an Octree algorithm
6257  */
6258 //================================================================================
6259
6260 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6261                                             const double         theTolerance,
6262                                             TListOfListOfNodes & theGroupsOfNodes)
6263 {
6264   myLastCreatedElems.Clear();
6265   myLastCreatedNodes.Clear();
6266
6267   if ( theNodes.empty() )
6268   { // get all nodes in the mesh
6269     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6270     while ( nIt->more() )
6271       theNodes.insert( theNodes.end(),nIt->next());
6272   }
6273
6274   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6275 }
6276
6277
6278 //=======================================================================
6279 /*!
6280  * \brief Implementation of search for the node closest to point
6281  */
6282 //=======================================================================
6283
6284 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6285 {
6286   //---------------------------------------------------------------------
6287   /*!
6288    * \brief Constructor
6289    */
6290   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6291   {
6292     myMesh = ( SMESHDS_Mesh* ) theMesh;
6293
6294     TIDSortedNodeSet nodes;
6295     if ( theMesh ) {
6296       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6297       while ( nIt->more() )
6298         nodes.insert( nodes.end(), nIt->next() );
6299     }
6300     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6301
6302     // get max size of a leaf box
6303     SMESH_OctreeNode* tree = myOctreeNode;
6304     while ( !tree->isLeaf() )
6305     {
6306       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6307       if ( cIt->more() )
6308         tree = cIt->next();
6309     }
6310     myHalfLeafSize = tree->maxSize() / 2.;
6311   }
6312
6313   //---------------------------------------------------------------------
6314   /*!
6315    * \brief Move node and update myOctreeNode accordingly
6316    */
6317   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6318   {
6319     myOctreeNode->UpdateByMoveNode( node, toPnt );
6320     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6321   }
6322
6323   //---------------------------------------------------------------------
6324   /*!
6325    * \brief Do it's job
6326    */
6327   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6328   {
6329     map<double, const SMDS_MeshNode*> dist2Nodes;
6330     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6331     if ( !dist2Nodes.empty() )
6332       return dist2Nodes.begin()->second;
6333     list<const SMDS_MeshNode*> nodes;
6334     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6335
6336     double minSqDist = DBL_MAX;
6337     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6338     {
6339       // sort leafs by their distance from thePnt
6340       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6341       TDistTreeMap treeMap;
6342       list< SMESH_OctreeNode* > treeList;
6343       list< SMESH_OctreeNode* >::iterator trIt;
6344       treeList.push_back( myOctreeNode );
6345
6346       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6347       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6348       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6349       {
6350         SMESH_OctreeNode* tree = *trIt;
6351         if ( !tree->isLeaf() ) // put children to the queue
6352         {
6353           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6354           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6355           while ( cIt->more() )
6356             treeList.push_back( cIt->next() );
6357         }
6358         else if ( tree->NbNodes() ) // put a tree to the treeMap
6359         {
6360           const Bnd_B3d& box = tree->getBox();
6361           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6362           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6363           if ( !it_in.second ) // not unique distance to box center
6364             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6365         }
6366       }
6367       // find distance after which there is no sense to check tree's
6368       double sqLimit = DBL_MAX;
6369       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6370       if ( treeMap.size() > 5 ) {
6371         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6372         const Bnd_B3d& box = closestTree->getBox();
6373         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6374         sqLimit = limit * limit;
6375       }
6376       // get all nodes from trees
6377       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6378         if ( sqDist_tree->first > sqLimit )
6379           break;
6380         SMESH_OctreeNode* tree = sqDist_tree->second;
6381         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6382       }
6383     }
6384     // find closest among nodes
6385     minSqDist = DBL_MAX;
6386     const SMDS_MeshNode* closestNode = 0;
6387     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6388     for ( ; nIt != nodes.end(); ++nIt ) {
6389       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6390       if ( minSqDist > sqDist ) {
6391         closestNode = *nIt;
6392         minSqDist = sqDist;
6393       }
6394     }
6395     return closestNode;
6396   }
6397
6398   //---------------------------------------------------------------------
6399   /*!
6400    * \brief Destructor
6401    */
6402   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6403
6404   //---------------------------------------------------------------------
6405   /*!
6406    * \brief Return the node tree
6407    */
6408   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6409
6410 private:
6411   SMESH_OctreeNode* myOctreeNode;
6412   SMESHDS_Mesh*     myMesh;
6413   double            myHalfLeafSize; // max size of a leaf box
6414 };
6415
6416 //=======================================================================
6417 /*!
6418  * \brief Return SMESH_NodeSearcher
6419  */
6420 //=======================================================================
6421
6422 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6423 {
6424   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6425 }
6426
6427 // ========================================================================
6428 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6429 {
6430   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6431   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6432   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6433
6434   //=======================================================================
6435   /*!
6436    * \brief Octal tree of bounding boxes of elements
6437    */
6438   //=======================================================================
6439
6440   class ElementBndBoxTree : public SMESH_Octree
6441   {
6442   public:
6443
6444     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6445     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6446     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6447     ~ElementBndBoxTree();
6448
6449   protected:
6450     ElementBndBoxTree() {}
6451     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6452     void buildChildrenData();
6453     Bnd_B3d* buildRootBox();
6454   private:
6455     //!< Bounding box of element
6456     struct ElementBox : public Bnd_B3d
6457     {
6458       const SMDS_MeshElement* _element;
6459       int                     _refCount; // an ElementBox can be included in several tree branches
6460       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6461     };
6462     vector< ElementBox* > _elements;
6463   };
6464
6465   //================================================================================
6466   /*!
6467    * \brief ElementBndBoxTree creation
6468    */
6469   //================================================================================
6470
6471   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6472     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6473   {
6474     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6475     _elements.reserve( nbElems );
6476
6477     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6478     while ( elemIt->more() )
6479       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6480
6481     if ( _elements.size() > MaxNbElemsInLeaf )
6482       compute();
6483     else
6484       myIsLeaf = true;
6485   }
6486
6487   //================================================================================
6488   /*!
6489    * \brief Destructor
6490    */
6491   //================================================================================
6492
6493   ElementBndBoxTree::~ElementBndBoxTree()
6494   {
6495     for ( int i = 0; i < _elements.size(); ++i )
6496       if ( --_elements[i]->_refCount <= 0 )
6497         delete _elements[i];
6498   }
6499
6500   //================================================================================
6501   /*!
6502    * \brief Return the maximal box
6503    */
6504   //================================================================================
6505
6506   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6507   {
6508     Bnd_B3d* box = new Bnd_B3d;
6509     for ( int i = 0; i < _elements.size(); ++i )
6510       box->Add( *_elements[i] );
6511     return box;
6512   }
6513
6514   //================================================================================
6515   /*!
6516    * \brief Redistrubute element boxes among children
6517    */
6518   //================================================================================
6519
6520   void ElementBndBoxTree::buildChildrenData()
6521   {
6522     for ( int i = 0; i < _elements.size(); ++i )
6523     {
6524       for (int j = 0; j < 8; j++)
6525       {
6526         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6527         {
6528           _elements[i]->_refCount++;
6529           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6530         }
6531       }
6532       _elements[i]->_refCount--;
6533     }
6534     _elements.clear();
6535
6536     for (int j = 0; j < 8; j++)
6537     {
6538       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6539       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6540         child->myIsLeaf = true;
6541
6542       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6543         child->_elements.resize( child->_elements.size() ); // compact
6544     }
6545   }
6546
6547   //================================================================================
6548   /*!
6549    * \brief Return elements which can include the point
6550    */
6551   //================================================================================
6552
6553   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6554                                                 TIDSortedElemSet& foundElems)
6555   {
6556     if ( level() && getBox().IsOut( point.XYZ() ))
6557       return;
6558
6559     if ( isLeaf() )
6560     {
6561       for ( int i = 0; i < _elements.size(); ++i )
6562         if ( !_elements[i]->IsOut( point.XYZ() ))
6563           foundElems.insert( _elements[i]->_element );
6564     }
6565     else
6566     {
6567       for (int i = 0; i < 8; i++)
6568         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6569     }
6570   }
6571
6572   //================================================================================
6573   /*!
6574    * \brief Return elements which can be intersected by the line
6575    */
6576   //================================================================================
6577
6578   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6579                                                TIDSortedElemSet& foundElems)
6580   {
6581     if ( level() && getBox().IsOut( line ))
6582       return;
6583
6584     if ( isLeaf() )
6585     {
6586       for ( int i = 0; i < _elements.size(); ++i )
6587         if ( !_elements[i]->IsOut( line ))
6588           foundElems.insert( _elements[i]->_element );
6589     }
6590     else
6591     {
6592       for (int i = 0; i < 8; i++)
6593         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6594     }
6595   }
6596
6597   //================================================================================
6598   /*!
6599    * \brief Construct the element box
6600    */
6601   //================================================================================
6602
6603   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6604   {
6605     _element  = elem;
6606     _refCount = 1;
6607     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6608     while ( nIt->more() )
6609       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6610     Enlarge( tolerance );
6611   }
6612
6613 } // namespace
6614
6615 //=======================================================================
6616 /*!
6617  * \brief Implementation of search for the elements by point and
6618  *        of classification of point in 2D mesh
6619  */
6620 //=======================================================================
6621
6622 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6623 {
6624   SMESHDS_Mesh*                _mesh;
6625   SMDS_ElemIteratorPtr         _meshPartIt;
6626   ElementBndBoxTree*           _ebbTree;
6627   SMESH_NodeSearcherImpl*      _nodeSearcher;
6628   SMDSAbs_ElementType          _elementType;
6629   double                       _tolerance;
6630   bool                         _outerFacesFound;
6631   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6632
6633   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6634     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6635   ~SMESH_ElementSearcherImpl()
6636   {
6637     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6638     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6639   }
6640   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6641                                   SMDSAbs_ElementType                type,
6642                                   vector< const SMDS_MeshElement* >& foundElements);
6643   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6644
6645   void GetElementsNearLine( const gp_Ax1&                      line,
6646                             SMDSAbs_ElementType                type,
6647                             vector< const SMDS_MeshElement* >& foundElems);
6648   double getTolerance();
6649   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6650                             const double tolerance, double & param);
6651   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6652   bool isOuterBoundary(const SMDS_MeshElement* face) const
6653   {
6654     return _outerFaces.empty() || _outerFaces.count(face);
6655   }
6656   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6657   {
6658     const SMDS_MeshElement* _face;
6659     gp_Vec                  _faceNorm;
6660     bool                    _coincides; //!< the line lays in face plane
6661     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6662       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6663   };
6664   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6665   {
6666     SMESH_TLink      _link;
6667     TIDSortedElemSet _faces;
6668     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6669       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6670   };
6671 };
6672
6673 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6674 {
6675   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6676              << ", _coincides="<<i._coincides << ")";
6677 }
6678
6679 //=======================================================================
6680 /*!
6681  * \brief define tolerance for search
6682  */
6683 //=======================================================================
6684
6685 double SMESH_ElementSearcherImpl::getTolerance()
6686 {
6687   if ( _tolerance < 0 )
6688   {
6689     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6690
6691     _tolerance = 0;
6692     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6693     {
6694       double boxSize = _nodeSearcher->getTree()->maxSize();
6695       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6696     }
6697     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6698     {
6699       double boxSize = _ebbTree->maxSize();
6700       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6701     }
6702     if ( _tolerance == 0 )
6703     {
6704       // define tolerance by size of a most complex element
6705       int complexType = SMDSAbs_Volume;
6706       while ( complexType > SMDSAbs_All &&
6707               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6708         --complexType;
6709       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6710       double elemSize;
6711       if ( complexType == int( SMDSAbs_Node ))
6712       {
6713         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6714         elemSize = 1;
6715         if ( meshInfo.NbNodes() > 2 )
6716           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6717       }
6718       else
6719       {
6720         SMDS_ElemIteratorPtr elemIt =
6721             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6722         const SMDS_MeshElement* elem = elemIt->next();
6723         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6724         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6725         elemSize = 0;
6726         while ( nodeIt->more() )
6727         {
6728           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6729           elemSize = max( dist, elemSize );
6730         }
6731       }
6732       _tolerance = 1e-4 * elemSize;
6733     }
6734   }
6735   return _tolerance;
6736 }
6737
6738 //================================================================================
6739 /*!
6740  * \brief Find intersection of the line and an edge of face and return parameter on line
6741  */
6742 //================================================================================
6743
6744 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6745                                                      const SMDS_MeshElement* face,
6746                                                      const double            tol,
6747                                                      double &                param)
6748 {
6749   int nbInts = 0;
6750   param = 0;
6751
6752   GeomAPI_ExtremaCurveCurve anExtCC;
6753   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6754   
6755   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6756   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6757   {
6758     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6759                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6760     anExtCC.Init( lineCurve, edge);
6761     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6762     {
6763       Quantity_Parameter pl, pe;
6764       anExtCC.LowerDistanceParameters( pl, pe );
6765       param += pl;
6766       if ( ++nbInts == 2 )
6767         break;
6768     }
6769   }
6770   if ( nbInts > 0 ) param /= nbInts;
6771   return nbInts > 0;
6772 }
6773 //================================================================================
6774 /*!
6775  * \brief Find all faces belonging to the outer boundary of mesh
6776  */
6777 //================================================================================
6778
6779 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6780 {
6781   if ( _outerFacesFound ) return;
6782
6783   // Collect all outer faces by passing from one outer face to another via their links
6784   // and BTW find out if there are internal faces at all.
6785
6786   // checked links and links where outer boundary meets internal one
6787   set< SMESH_TLink > visitedLinks, seamLinks;
6788
6789   // links to treat with already visited faces sharing them
6790   list < TFaceLink > startLinks;
6791
6792   // load startLinks with the first outerFace
6793   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6794   _outerFaces.insert( outerFace );
6795
6796   TIDSortedElemSet emptySet;
6797   while ( !startLinks.empty() )
6798   {
6799     const SMESH_TLink& link  = startLinks.front()._link;
6800     TIDSortedElemSet&  faces = startLinks.front()._faces;
6801
6802     outerFace = *faces.begin();
6803     // find other faces sharing the link
6804     const SMDS_MeshElement* f;
6805     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6806       faces.insert( f );
6807
6808     // select another outer face among the found 
6809     const SMDS_MeshElement* outerFace2 = 0;
6810     if ( faces.size() == 2 )
6811     {
6812       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6813     }
6814     else if ( faces.size() > 2 )
6815     {
6816       seamLinks.insert( link );
6817
6818       // link direction within the outerFace
6819       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6820                    SMESH_TNodeXYZ( link.node2()));
6821       int i1 = outerFace->GetNodeIndex( link.node1() );
6822       int i2 = outerFace->GetNodeIndex( link.node2() );
6823       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6824       if ( rev ) n1n2.Reverse();
6825       // outerFace normal
6826       gp_XYZ ofNorm, fNorm;
6827       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6828       {
6829         // direction from the link inside outerFace
6830         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6831         // sort all other faces by angle with the dirInOF
6832         map< double, const SMDS_MeshElement* > angle2Face;
6833         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6834         for ( ; face != faces.end(); ++face )
6835         {
6836           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6837             continue;
6838           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6839           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6840           if ( angle < 0 ) angle += 2*PI;
6841           angle2Face.insert( make_pair( angle, *face ));
6842         }
6843         if ( !angle2Face.empty() )
6844           outerFace2 = angle2Face.begin()->second;
6845       }
6846     }
6847     // store the found outer face and add its links to continue seaching from
6848     if ( outerFace2 )
6849     {
6850       _outerFaces.insert( outerFace );
6851       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6852       for ( int i = 0; i < nbNodes; ++i )
6853       {
6854         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6855         if ( visitedLinks.insert( link2 ).second )
6856           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6857       }
6858     }
6859     startLinks.pop_front();
6860   }
6861   _outerFacesFound = true;
6862
6863   if ( !seamLinks.empty() )
6864   {
6865     // There are internal boundaries touching the outher one,
6866     // find all faces of internal boundaries in order to find
6867     // faces of boundaries of holes, if any.
6868     
6869   }
6870   else
6871   {
6872     _outerFaces.clear();
6873   }
6874 }
6875
6876 //=======================================================================
6877 /*!
6878  * \brief Find elements of given type where the given point is IN or ON.
6879  *        Returns nb of found elements and elements them-selves.
6880  *
6881  * 'ALL' type means elements of any type excluding nodes and 0D elements
6882  */
6883 //=======================================================================
6884
6885 int SMESH_ElementSearcherImpl::
6886 FindElementsByPoint(const gp_Pnt&                      point,
6887                     SMDSAbs_ElementType                type,
6888                     vector< const SMDS_MeshElement* >& foundElements)
6889 {
6890   foundElements.clear();
6891
6892   double tolerance = getTolerance();
6893
6894   // =================================================================================
6895   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6896   {
6897     if ( !_nodeSearcher )
6898       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6899
6900     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6901     if ( !closeNode ) return foundElements.size();
6902
6903     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6904       return foundElements.size(); // to far from any node
6905
6906     if ( type == SMDSAbs_Node )
6907     {
6908       foundElements.push_back( closeNode );
6909     }
6910     else
6911     {
6912       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6913       while ( elemIt->more() )
6914         foundElements.push_back( elemIt->next() );
6915     }
6916   }
6917   // =================================================================================
6918   else // elements more complex than 0D
6919   {
6920     if ( !_ebbTree || _elementType != type )
6921     {
6922       if ( _ebbTree ) delete _ebbTree;
6923       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6924     }
6925     TIDSortedElemSet suspectElems;
6926     _ebbTree->getElementsNearPoint( point, suspectElems );
6927     TIDSortedElemSet::iterator elem = suspectElems.begin();
6928     for ( ; elem != suspectElems.end(); ++elem )
6929       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6930         foundElements.push_back( *elem );
6931   }
6932   return foundElements.size();
6933 }
6934
6935 //================================================================================
6936 /*!
6937  * \brief Classify the given point in the closed 2D mesh
6938  */
6939 //================================================================================
6940
6941 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6942 {
6943   double tolerance = getTolerance();
6944   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6945   {
6946     if ( _ebbTree ) delete _ebbTree;
6947     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6948   }
6949   // Algo: analyse transition of a line starting at the point through mesh boundary;
6950   // try three lines parallel to axis of the coordinate system and perform rough
6951   // analysis. If solution is not clear perform thorough analysis.
6952
6953   const int nbAxes = 3;
6954   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6955   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6956   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6957   multimap< int, int > nbInt2Axis; // to find the simplest case
6958   for ( int axis = 0; axis < nbAxes; ++axis )
6959   {
6960     gp_Ax1 lineAxis( point, axisDir[axis]);
6961     gp_Lin line    ( lineAxis );
6962
6963     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6964     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6965
6966     // Intersect faces with the line
6967
6968     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6969     TIDSortedElemSet::iterator face = suspectFaces.begin();
6970     for ( ; face != suspectFaces.end(); ++face )
6971     {
6972       // get face plane
6973       gp_XYZ fNorm;
6974       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6975       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6976
6977       // perform intersection
6978       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6979       if ( !intersection.IsDone() )
6980         continue;
6981       if ( intersection.IsInQuadric() )
6982       {
6983         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6984       }
6985       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6986       {
6987         gp_Pnt intersectionPoint = intersection.Point(1);
6988         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6989           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6990       }
6991     }
6992     // Analyse intersections roughly
6993
6994     int nbInter = u2inters.size();
6995     if ( nbInter == 0 )
6996       return TopAbs_OUT; 
6997
6998     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6999     if ( nbInter == 1 ) // not closed mesh
7000       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
7001
7002     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
7003       return TopAbs_ON;
7004
7005     if ( (f<0) == (l<0) )
7006       return TopAbs_OUT;
7007
7008     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
7009     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
7010     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
7011       return TopAbs_IN;
7012
7013     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
7014
7015     if ( _outerFacesFound ) break; // pass to thorough analysis
7016
7017   } // three attempts - loop on CS axes
7018
7019   // Analyse intersections thoroughly.
7020   // We make two loops maximum, on the first one we only exclude touching intersections,
7021   // on the second, if situation is still unclear, we gather and use information on
7022   // position of faces (internal or outer). If faces position is already gathered,
7023   // we make the second loop right away.
7024
7025   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
7026   {
7027     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
7028     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
7029     {
7030       int axis = nb_axis->second;
7031       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
7032
7033       gp_Ax1 lineAxis( point, axisDir[axis]);
7034       gp_Lin line    ( lineAxis );
7035
7036       // add tangent intersections to u2inters
7037       double param;
7038       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
7039       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
7040         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
7041           u2inters.insert(make_pair( param, *tgtInt ));
7042       tangentInters[ axis ].clear();
7043
7044       // Count intersections before and after the point excluding touching ones.
7045       // If hasPositionInfo we count intersections of outer boundary only
7046
7047       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
7048       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
7049       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
7050       bool ok = ! u_int1->second._coincides;
7051       while ( ok && u_int1 != u2inters.end() )
7052       {
7053         double u = u_int1->first;
7054         bool touchingInt = false;
7055         if ( ++u_int2 != u2inters.end() )
7056         {
7057           // skip intersections at the same point (if the line passes through edge or node)
7058           int nbSamePnt = 0;
7059           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
7060           {
7061             ++nbSamePnt;
7062             ++u_int2;
7063           }
7064
7065           // skip tangent intersections
7066           int nbTgt = 0;
7067           const SMDS_MeshElement* prevFace = u_int1->second._face;
7068           while ( ok && u_int2->second._coincides )
7069           {
7070             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
7071               ok = false;
7072             else
7073             {
7074               nbTgt++;
7075               u_int2++;
7076               ok = ( u_int2 != u2inters.end() );
7077             }
7078           }
7079           if ( !ok ) break;
7080
7081           // skip intersections at the same point after tangent intersections
7082           if ( nbTgt > 0 )
7083           {
7084             double u2 = u_int2->first;
7085             ++u_int2;
7086             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
7087             {
7088               ++nbSamePnt;
7089               ++u_int2;
7090             }
7091           }
7092           // decide if we skipped a touching intersection
7093           if ( nbSamePnt + nbTgt > 0 )
7094           {
7095             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
7096             map< double, TInters >::iterator u_int = u_int1;
7097             for ( ; u_int != u_int2; ++u_int )
7098             {
7099               if ( u_int->second._coincides ) continue;
7100               double dot = u_int->second._faceNorm * line.Direction();
7101               if ( dot > maxDot ) maxDot = dot;
7102               if ( dot < minDot ) minDot = dot;
7103             }
7104             touchingInt = ( minDot*maxDot < 0 );
7105           }
7106         }
7107         if ( !touchingInt )
7108         {
7109           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
7110           {
7111             if ( u < 0 )
7112               ++nbIntBeforePoint;
7113             else
7114               ++nbIntAfterPoint;
7115           }
7116           if ( u < f ) f = u;
7117           if ( u > l ) l = u;
7118         }
7119
7120         u_int1 = u_int2; // to next intersection
7121
7122       } // loop on intersections with one line
7123
7124       if ( ok )
7125       {
7126         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
7127           return TopAbs_ON;
7128
7129         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
7130           return TopAbs_OUT; 
7131
7132         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
7133           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
7134
7135         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
7136           return TopAbs_IN;
7137
7138         if ( (f<0) == (l<0) )
7139           return TopAbs_OUT;
7140
7141         if ( hasPositionInfo )
7142           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7143       }
7144     } // loop on intersections of the tree lines - thorough analysis
7145
7146     if ( !hasPositionInfo )
7147     {
7148       // gather info on faces position - is face in the outer boundary or not
7149       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7150       findOuterBoundary( u2inters.begin()->second._face );
7151     }
7152
7153   } // two attempts - with and w/o faces position info in the mesh
7154
7155   return TopAbs_UNKNOWN;
7156 }
7157
7158 //=======================================================================
7159 /*!
7160  * \brief Return elements possibly intersecting the line
7161  */
7162 //=======================================================================
7163
7164 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7165                                                      SMDSAbs_ElementType                type,
7166                                                      vector< const SMDS_MeshElement* >& foundElems)
7167 {
7168   if ( !_ebbTree || _elementType != type )
7169   {
7170     if ( _ebbTree ) delete _ebbTree;
7171     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7172   }
7173   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7174   _ebbTree->getElementsNearLine( line, suspectFaces );
7175   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7176 }
7177
7178 //=======================================================================
7179 /*!
7180  * \brief Return SMESH_ElementSearcher
7181  */
7182 //=======================================================================
7183
7184 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7185 {
7186   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7187 }
7188
7189 //=======================================================================
7190 /*!
7191  * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
7192  */
7193 //=======================================================================
7194
7195 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7196 {
7197   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7198 }
7199
7200 //=======================================================================
7201 /*!
7202  * \brief Return true if the point is IN or ON of the element
7203  */
7204 //=======================================================================
7205
7206 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7207 {
7208   if ( element->GetType() == SMDSAbs_Volume)
7209   {
7210     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7211   }
7212
7213   // get ordered nodes
7214
7215   vector< gp_XYZ > xyz;
7216   vector<const SMDS_MeshNode*> nodeList;
7217
7218   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7219   if ( element->IsQuadratic() ) {
7220     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7221       nodeIt = f->interlacedNodesElemIterator();
7222     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7223       nodeIt = e->interlacedNodesElemIterator();
7224   }
7225   while ( nodeIt->more() )
7226     {
7227       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7228       xyz.push_back( SMESH_TNodeXYZ(node) );
7229       nodeList.push_back(node);
7230     }
7231
7232   int i, nbNodes = element->NbNodes();
7233
7234   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7235   {
7236     // compute face normal
7237     gp_Vec faceNorm(0,0,0);
7238     xyz.push_back( xyz.front() );
7239     nodeList.push_back( nodeList.front() );
7240     for ( i = 0; i < nbNodes; ++i )
7241     {
7242       gp_Vec edge1( xyz[i+1], xyz[i]);
7243       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7244       faceNorm += edge1 ^ edge2;
7245     }
7246     double normSize = faceNorm.Magnitude();
7247     if ( normSize <= tol )
7248     {
7249       // degenerated face: point is out if it is out of all face edges
7250       for ( i = 0; i < nbNodes; ++i )
7251       {
7252         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7253         if ( !isOut( &edge, point, tol ))
7254           return false;
7255       }
7256       return true;
7257     }
7258     faceNorm /= normSize;
7259
7260     // check if the point lays on face plane
7261     gp_Vec n2p( xyz[0], point );
7262     if ( fabs( n2p * faceNorm ) > tol )
7263       return true; // not on face plane
7264
7265     // check if point is out of face boundary:
7266     // define it by closest transition of a ray point->infinity through face boundary
7267     // on the face plane.
7268     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7269     // to find intersections of the ray with the boundary.
7270     gp_Vec ray = n2p;
7271     gp_Vec plnNorm = ray ^ faceNorm;
7272     normSize = plnNorm.Magnitude();
7273     if ( normSize <= tol ) return false; // point coincides with the first node
7274     plnNorm /= normSize;
7275     // for each node of the face, compute its signed distance to the plane
7276     vector<double> dist( nbNodes + 1);
7277     for ( i = 0; i < nbNodes; ++i )
7278     {
7279       gp_Vec n2p( xyz[i], point );
7280       dist[i] = n2p * plnNorm;
7281     }
7282     dist.back() = dist.front();
7283     // find the closest intersection
7284     int    iClosest = -1;
7285     double rClosest, distClosest = 1e100;;
7286     gp_Pnt pClosest;
7287     for ( i = 0; i < nbNodes; ++i )
7288     {
7289       double r;
7290       if ( fabs( dist[i]) < tol )
7291         r = 0.;
7292       else if ( fabs( dist[i+1]) < tol )
7293         r = 1.;
7294       else if ( dist[i] * dist[i+1] < 0 )
7295         r = dist[i] / ( dist[i] - dist[i+1] );
7296       else
7297         continue; // no intersection
7298       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7299       gp_Vec p2int ( point, pInt);
7300       if ( p2int * ray > -tol ) // right half-space
7301       {
7302         double intDist = p2int.SquareMagnitude();
7303         if ( intDist < distClosest )
7304         {
7305           iClosest = i;
7306           rClosest = r;
7307           pClosest = pInt;
7308           distClosest = intDist;
7309         }
7310       }
7311     }
7312     if ( iClosest < 0 )
7313       return true; // no intesections - out
7314
7315     // analyse transition
7316     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7317     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7318     gp_Vec p2int ( point, pClosest );
7319     bool out = (edgeNorm * p2int) < -tol;
7320     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7321       return out;
7322
7323     // ray pass through a face node; analyze transition through an adjacent edge
7324     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7325     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7326     gp_Vec edgeAdjacent( p1, p2 );
7327     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7328     bool out2 = (edgeNorm2 * p2int) < -tol;
7329
7330     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7331     return covexCorner ? (out || out2) : (out && out2);
7332   }
7333   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7334   {
7335     // point is out of edge if it is NOT ON any straight part of edge
7336     // (we consider quadratic edge as being composed of two straight parts)
7337     for ( i = 1; i < nbNodes; ++i )
7338     {
7339       gp_Vec edge( xyz[i-1], xyz[i]);
7340       gp_Vec n1p ( xyz[i-1], point);
7341       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7342       if ( dist > tol )
7343         continue;
7344       gp_Vec n2p( xyz[i], point );
7345       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7346         continue;
7347       return false; // point is ON this part
7348     }
7349     return true;
7350   }
7351   // Node or 0D element -------------------------------------------------------------------------
7352   {
7353     gp_Vec n2p ( xyz[0], point );
7354     return n2p.Magnitude() <= tol;
7355   }
7356   return true;
7357 }
7358
7359 //=======================================================================
7360 //function : SimplifyFace
7361 //purpose  :
7362 //=======================================================================
7363 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7364                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7365                                     vector<int>&                        quantities) const
7366 {
7367   int nbNodes = faceNodes.size();
7368
7369   if (nbNodes < 3)
7370     return 0;
7371
7372   set<const SMDS_MeshNode*> nodeSet;
7373
7374   // get simple seq of nodes
7375   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7376   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7377   int iSimple = 0, nbUnique = 0;
7378
7379   simpleNodes[iSimple++] = faceNodes[0];
7380   nbUnique++;
7381   for (int iCur = 1; iCur < nbNodes; iCur++) {
7382     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7383       simpleNodes[iSimple++] = faceNodes[iCur];
7384       if (nodeSet.insert( faceNodes[iCur] ).second)
7385         nbUnique++;
7386     }
7387   }
7388   int nbSimple = iSimple;
7389   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7390     nbSimple--;
7391     iSimple--;
7392   }
7393
7394   if (nbUnique < 3)
7395     return 0;
7396
7397   // separate loops
7398   int nbNew = 0;
7399   bool foundLoop = (nbSimple > nbUnique);
7400   while (foundLoop) {
7401     foundLoop = false;
7402     set<const SMDS_MeshNode*> loopSet;
7403     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7404       const SMDS_MeshNode* n = simpleNodes[iSimple];
7405       if (!loopSet.insert( n ).second) {
7406         foundLoop = true;
7407
7408         // separate loop
7409         int iC = 0, curLast = iSimple;
7410         for (; iC < curLast; iC++) {
7411           if (simpleNodes[iC] == n) break;
7412         }
7413         int loopLen = curLast - iC;
7414         if (loopLen > 2) {
7415           // create sub-element
7416           nbNew++;
7417           quantities.push_back(loopLen);
7418           for (; iC < curLast; iC++) {
7419             poly_nodes.push_back(simpleNodes[iC]);
7420           }
7421         }
7422         // shift the rest nodes (place from the first loop position)
7423         for (iC = curLast + 1; iC < nbSimple; iC++) {
7424           simpleNodes[iC - loopLen] = simpleNodes[iC];
7425         }
7426         nbSimple -= loopLen;
7427         iSimple -= loopLen;
7428       }
7429     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7430   } // while (foundLoop)
7431
7432   if (iSimple > 2) {
7433     nbNew++;
7434     quantities.push_back(iSimple);
7435     for (int i = 0; i < iSimple; i++)
7436       poly_nodes.push_back(simpleNodes[i]);
7437   }
7438
7439   return nbNew;
7440 }
7441
7442 //=======================================================================
7443 //function : MergeNodes
7444 //purpose  : In each group, the cdr of nodes are substituted by the first one
7445 //           in all elements.
7446 //=======================================================================
7447
7448 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7449 {
7450   MESSAGE("MergeNodes");
7451   myLastCreatedElems.Clear();
7452   myLastCreatedNodes.Clear();
7453
7454   SMESHDS_Mesh* aMesh = GetMeshDS();
7455
7456   TNodeNodeMap nodeNodeMap; // node to replace - new node
7457   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7458   list< int > rmElemIds, rmNodeIds;
7459
7460   // Fill nodeNodeMap and elems
7461
7462   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7463   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7464     list<const SMDS_MeshNode*>& nodes = *grIt;
7465     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7466     const SMDS_MeshNode* nToKeep = *nIt;
7467     //MESSAGE("node to keep " << nToKeep->GetID());
7468     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7469       const SMDS_MeshNode* nToRemove = *nIt;
7470       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7471       if ( nToRemove != nToKeep ) {
7472         //MESSAGE("  node to remove " << nToRemove->GetID());
7473         rmNodeIds.push_back( nToRemove->GetID() );
7474         AddToSameGroups( nToKeep, nToRemove, aMesh );
7475       }
7476
7477       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7478       while ( invElemIt->more() ) {
7479         const SMDS_MeshElement* elem = invElemIt->next();
7480         elems.insert(elem);
7481       }
7482     }
7483   }
7484   // Change element nodes or remove an element
7485
7486   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7487   for ( ; eIt != elems.end(); eIt++ ) {
7488     const SMDS_MeshElement* elem = *eIt;
7489     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7490     int nbNodes = elem->NbNodes();
7491     int aShapeId = FindShape( elem );
7492
7493     set<const SMDS_MeshNode*> nodeSet;
7494     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7495     int iUnique = 0, iCur = 0, nbRepl = 0;
7496     vector<int> iRepl( nbNodes );
7497
7498     // get new seq of nodes
7499     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7500     while ( itN->more() ) {
7501       const SMDS_MeshNode* n =
7502         static_cast<const SMDS_MeshNode*>( itN->next() );
7503
7504       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7505       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7506         n = (*nnIt).second;
7507         // BUG 0020185: begin
7508         {
7509           bool stopRecur = false;
7510           set<const SMDS_MeshNode*> nodesRecur;
7511           nodesRecur.insert(n);
7512           while (!stopRecur) {
7513             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7514             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7515               n = (*nnIt_i).second;
7516               if (!nodesRecur.insert(n).second) {
7517                 // error: recursive dependancy
7518                 stopRecur = true;
7519               }
7520             }
7521             else
7522               stopRecur = true;
7523           }
7524         }
7525         // BUG 0020185: end
7526         iRepl[ nbRepl++ ] = iCur;
7527       }
7528       curNodes[ iCur ] = n;
7529       bool isUnique = nodeSet.insert( n ).second;
7530       if ( isUnique ) {
7531         uniqueNodes[ iUnique++ ] = n;
7532         if ( nbRepl && iRepl[ nbRepl-1 ] == iCur )
7533           --nbRepl; // n do not stick to a node of the elem
7534       }
7535       iCur++;
7536     }
7537
7538     // Analyse element topology after replacement
7539
7540     bool isOk = true;
7541     int nbUniqueNodes = nodeSet.size();
7542     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7543     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7544       // Polygons and Polyhedral volumes
7545       if (elem->IsPoly()) {
7546
7547         if (elem->GetType() == SMDSAbs_Face) {
7548           // Polygon
7549           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7550           int inode = 0;
7551           for (; inode < nbNodes; inode++) {
7552             face_nodes[inode] = curNodes[inode];
7553           }
7554
7555           vector<const SMDS_MeshNode *> polygons_nodes;
7556           vector<int> quantities;
7557           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7558           if (nbNew > 0) {
7559             inode = 0;
7560             for (int iface = 0; iface < nbNew; iface++) {
7561               int nbNodes = quantities[iface];
7562               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7563               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7564                 poly_nodes[ii] = polygons_nodes[inode];
7565               }
7566               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7567               myLastCreatedElems.Append(newElem);
7568               if (aShapeId)
7569                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7570             }
7571
7572             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7573             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7574             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7575             int quid =0;
7576             if (nbNew > 0) quid = nbNew - 1;
7577             vector<int> newquant(quantities.begin()+quid, quantities.end());
7578             const SMDS_MeshElement* newElem = 0;
7579             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7580             myLastCreatedElems.Append(newElem);
7581             if ( aShapeId && newElem )
7582               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7583             rmElemIds.push_back(elem->GetID());
7584           }
7585           else {
7586             rmElemIds.push_back(elem->GetID());
7587           }
7588
7589         }
7590         else if (elem->GetType() == SMDSAbs_Volume) {
7591           // Polyhedral volume
7592           if (nbUniqueNodes < 4) {
7593             rmElemIds.push_back(elem->GetID());
7594           }
7595           else {
7596             // each face has to be analyzed in order to check volume validity
7597             const SMDS_VtkVolume* aPolyedre =
7598               dynamic_cast<const SMDS_VtkVolume*>( elem );
7599             if (aPolyedre) {
7600               int nbFaces = aPolyedre->NbFaces();
7601
7602               vector<const SMDS_MeshNode *> poly_nodes;
7603               vector<int> quantities;
7604
7605               for (int iface = 1; iface <= nbFaces; iface++) {
7606                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7607                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7608
7609                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7610                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7611                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7612                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7613                     faceNode = (*nnIt).second;
7614                   }
7615                   faceNodes[inode - 1] = faceNode;
7616                 }
7617
7618                 SimplifyFace(faceNodes, poly_nodes, quantities);
7619               }
7620
7621               if (quantities.size() > 3) {
7622                 // to be done: remove coincident faces
7623               }
7624
7625               if (quantities.size() > 3)
7626                 {
7627                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7628                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7629                   const SMDS_MeshElement* newElem = 0;
7630                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7631                   myLastCreatedElems.Append(newElem);
7632                   if ( aShapeId && newElem )
7633                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7634                   rmElemIds.push_back(elem->GetID());
7635                 }
7636             }
7637             else {
7638               rmElemIds.push_back(elem->GetID());
7639             }
7640           }
7641         }
7642         else {
7643         }
7644
7645         continue;
7646       } // poly element
7647
7648       // Regular elements
7649       // TODO not all the possible cases are solved. Find something more generic?
7650       switch ( nbNodes ) {
7651       case 2: ///////////////////////////////////// EDGE
7652         isOk = false; break;
7653       case 3: ///////////////////////////////////// TRIANGLE
7654         isOk = false; break;
7655       case 4:
7656         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7657           isOk = false;
7658         else { //////////////////////////////////// QUADRANGLE
7659           if ( nbUniqueNodes < 3 )
7660             isOk = false;
7661           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7662             isOk = false; // opposite nodes stick
7663           //MESSAGE("isOk " << isOk);
7664         }
7665         break;
7666       case 6: ///////////////////////////////////// PENTAHEDRON
7667         if ( nbUniqueNodes == 4 ) {
7668           // ---------------------------------> tetrahedron
7669           if (nbRepl == 3 &&
7670               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7671             // all top nodes stick: reverse a bottom
7672             uniqueNodes[ 0 ] = curNodes [ 1 ];
7673             uniqueNodes[ 1 ] = curNodes [ 0 ];
7674           }
7675           else if (nbRepl == 3 &&
7676                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7677             // all bottom nodes stick: set a top before
7678             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7679             uniqueNodes[ 0 ] = curNodes [ 3 ];
7680             uniqueNodes[ 1 ] = curNodes [ 4 ];
7681             uniqueNodes[ 2 ] = curNodes [ 5 ];
7682           }
7683           else if (nbRepl == 4 &&
7684                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7685             // a lateral face turns into a line: reverse a bottom
7686             uniqueNodes[ 0 ] = curNodes [ 1 ];
7687             uniqueNodes[ 1 ] = curNodes [ 0 ];
7688           }
7689           else
7690             isOk = false;
7691         }
7692         else if ( nbUniqueNodes == 5 ) {
7693           // PENTAHEDRON --------------------> 2 tetrahedrons
7694           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7695             // a bottom node sticks with a linked top one
7696             // 1.
7697             SMDS_MeshElement* newElem =
7698               aMesh->AddVolume(curNodes[ 3 ],
7699                                curNodes[ 4 ],
7700                                curNodes[ 5 ],
7701                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7702             myLastCreatedElems.Append(newElem);
7703             if ( aShapeId )
7704               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7705             // 2. : reverse a bottom
7706             uniqueNodes[ 0 ] = curNodes [ 1 ];
7707             uniqueNodes[ 1 ] = curNodes [ 0 ];
7708             nbUniqueNodes = 4;
7709           }
7710           else
7711             isOk = false;
7712         }
7713         else
7714           isOk = false;
7715         break;
7716       case 8: {
7717         if(elem->IsQuadratic()) { // Quadratic quadrangle
7718           //   1    5    2
7719           //    +---+---+
7720           //    |       |
7721           //    |       |
7722           //   4+       +6
7723           //    |       |
7724           //    |       |
7725           //    +---+---+
7726           //   0    7    3
7727           isOk = false;
7728           if(nbRepl==2) {
7729             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7730           }
7731           if(nbRepl==3) {
7732             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7733             nbUniqueNodes = 6;
7734             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7735               uniqueNodes[0] = curNodes[0];
7736               uniqueNodes[1] = curNodes[2];
7737               uniqueNodes[2] = curNodes[3];
7738               uniqueNodes[3] = curNodes[5];
7739               uniqueNodes[4] = curNodes[6];
7740               uniqueNodes[5] = curNodes[7];
7741               isOk = true;
7742             }
7743             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7744               uniqueNodes[0] = curNodes[0];
7745               uniqueNodes[1] = curNodes[1];
7746               uniqueNodes[2] = curNodes[2];
7747               uniqueNodes[3] = curNodes[4];
7748               uniqueNodes[4] = curNodes[5];
7749               uniqueNodes[5] = curNodes[6];
7750               isOk = true;
7751             }
7752             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7753               uniqueNodes[0] = curNodes[1];
7754               uniqueNodes[1] = curNodes[2];
7755               uniqueNodes[2] = curNodes[3];
7756               uniqueNodes[3] = curNodes[5];
7757               uniqueNodes[4] = curNodes[6];
7758               uniqueNodes[5] = curNodes[0];
7759               isOk = true;
7760             }
7761             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7762               uniqueNodes[0] = curNodes[0];
7763               uniqueNodes[1] = curNodes[1];
7764               uniqueNodes[2] = curNodes[3];
7765               uniqueNodes[3] = curNodes[4];
7766               uniqueNodes[4] = curNodes[6];
7767               uniqueNodes[5] = curNodes[7];
7768               isOk = true;
7769             }
7770             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7771               uniqueNodes[0] = curNodes[0];
7772               uniqueNodes[1] = curNodes[2];
7773               uniqueNodes[2] = curNodes[3];
7774               uniqueNodes[3] = curNodes[1];
7775               uniqueNodes[4] = curNodes[6];
7776               uniqueNodes[5] = curNodes[7];
7777               isOk = true;
7778             }
7779             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7780               uniqueNodes[0] = curNodes[0];
7781               uniqueNodes[1] = curNodes[1];
7782               uniqueNodes[2] = curNodes[2];
7783               uniqueNodes[3] = curNodes[4];
7784               uniqueNodes[4] = curNodes[5];
7785               uniqueNodes[5] = curNodes[7];
7786               isOk = true;
7787             }
7788             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7789               uniqueNodes[0] = curNodes[0];
7790               uniqueNodes[1] = curNodes[1];
7791               uniqueNodes[2] = curNodes[3];
7792               uniqueNodes[3] = curNodes[4];
7793               uniqueNodes[4] = curNodes[2];
7794               uniqueNodes[5] = curNodes[7];
7795               isOk = true;
7796             }
7797             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7798               uniqueNodes[0] = curNodes[0];
7799               uniqueNodes[1] = curNodes[1];
7800               uniqueNodes[2] = curNodes[2];
7801               uniqueNodes[3] = curNodes[4];
7802               uniqueNodes[4] = curNodes[5];
7803               uniqueNodes[5] = curNodes[3];
7804               isOk = true;
7805             }
7806           }
7807           if(nbRepl==4) {
7808             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7809           }
7810           if(nbRepl==5) {
7811             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7812           }
7813           break;
7814         }
7815         //////////////////////////////////// HEXAHEDRON
7816         isOk = false;
7817         SMDS_VolumeTool hexa (elem);
7818         hexa.SetExternalNormal();
7819         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7820           //////////////////////// HEX ---> 1 tetrahedron
7821           for ( int iFace = 0; iFace < 6; iFace++ ) {
7822             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7823             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7824                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7825                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7826               // one face turns into a point ...
7827               int iOppFace = hexa.GetOppFaceIndex( iFace );
7828               ind = hexa.GetFaceNodesIndices( iOppFace );
7829               int nbStick = 0;
7830               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7831                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7832                   nbStick++;
7833               }
7834               if ( nbStick == 1 ) {
7835                 // ... and the opposite one - into a triangle.
7836                 // set a top node
7837                 ind = hexa.GetFaceNodesIndices( iFace );
7838                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7839                 isOk = true;
7840               }
7841               break;
7842             }
7843           }
7844         }
7845         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7846           //////////////////////// HEX ---> 1 prism
7847           int nbTria = 0, iTria[3];
7848           const int *ind; // indices of face nodes
7849           // look for triangular faces
7850           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7851             ind = hexa.GetFaceNodesIndices( iFace );
7852             TIDSortedNodeSet faceNodes;
7853             for ( iCur = 0; iCur < 4; iCur++ )
7854               faceNodes.insert( curNodes[ind[iCur]] );
7855             if ( faceNodes.size() == 3 )
7856               iTria[ nbTria++ ] = iFace;
7857           }
7858           // check if triangles are opposite
7859           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7860           {
7861             isOk = true;
7862             // set nodes of the bottom triangle
7863             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7864             vector<int> indB;
7865             for ( iCur = 0; iCur < 4; iCur++ )
7866               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7867                 indB.push_back( ind[iCur] );
7868             if ( !hexa.IsForward() )
7869               std::swap( indB[0], indB[2] );
7870             for ( iCur = 0; iCur < 3; iCur++ )
7871               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7872             // set nodes of the top triangle
7873             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7874             for ( iCur = 0; iCur < 3; ++iCur )
7875               for ( int j = 0; j < 4; ++j )
7876                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7877                 {
7878                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7879                   break;
7880                 }
7881           }
7882           break;
7883         }
7884         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7885           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7886           for ( int iFace = 0; iFace < 6; iFace++ ) {
7887             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7888             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7889                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7890                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7891               // one face turns into a point ...
7892               int iOppFace = hexa.GetOppFaceIndex( iFace );
7893               ind = hexa.GetFaceNodesIndices( iOppFace );
7894               int nbStick = 0;
7895               iUnique = 2;  // reverse a tetrahedron 1 bottom
7896               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7897                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7898                   nbStick++;
7899                 else if ( iUnique >= 0 )
7900                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7901               }
7902               if ( nbStick == 0 ) {
7903                 // ... and the opposite one is a quadrangle
7904                 // set a top node
7905                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7906                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7907                 nbUniqueNodes = 4;
7908                 // tetrahedron 2
7909                 SMDS_MeshElement* newElem =
7910                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7911                                    curNodes[ind[ 3 ]],
7912                                    curNodes[ind[ 2 ]],
7913                                    curNodes[indTop[ 0 ]]);
7914                 myLastCreatedElems.Append(newElem);
7915                 if ( aShapeId )
7916                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7917                 isOk = true;
7918               }
7919               break;
7920             }
7921           }
7922         }
7923         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7924           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7925           // find indices of quad and tri faces
7926           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7927           for ( iFace = 0; iFace < 6; iFace++ ) {
7928             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7929             nodeSet.clear();
7930             for ( iCur = 0; iCur < 4; iCur++ )
7931               nodeSet.insert( curNodes[ind[ iCur ]] );
7932             nbUniqueNodes = nodeSet.size();
7933             if ( nbUniqueNodes == 3 )
7934               iTriFace[ nbTri++ ] = iFace;
7935             else if ( nbUniqueNodes == 4 )
7936               iQuadFace[ nbQuad++ ] = iFace;
7937           }
7938           if (nbQuad == 2 && nbTri == 4 &&
7939               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7940             // 2 opposite quadrangles stuck with a diagonal;
7941             // sample groups of merged indices: (0-4)(2-6)
7942             // --------------------------------------------> 2 tetrahedrons
7943             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7944             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7945             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7946             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7947                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7948               // stuck with 0-2 diagonal
7949               i0  = ind1[ 3 ];
7950               i1d = ind1[ 0 ];
7951               i2  = ind1[ 1 ];
7952               i3d = ind1[ 2 ];
7953               i0t = ind2[ 1 ];
7954               i2t = ind2[ 3 ];
7955             }
7956             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7957                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7958               // stuck with 1-3 diagonal
7959               i0  = ind1[ 0 ];
7960               i1d = ind1[ 1 ];
7961               i2  = ind1[ 2 ];
7962               i3d = ind1[ 3 ];
7963               i0t = ind2[ 0 ];
7964               i2t = ind2[ 1 ];
7965             }
7966             else {
7967               ASSERT(0);
7968             }
7969             // tetrahedron 1
7970             uniqueNodes[ 0 ] = curNodes [ i0 ];
7971             uniqueNodes[ 1 ] = curNodes [ i1d ];
7972             uniqueNodes[ 2 ] = curNodes [ i3d ];
7973             uniqueNodes[ 3 ] = curNodes [ i0t ];
7974             nbUniqueNodes = 4;
7975             // tetrahedron 2
7976             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7977                                                          curNodes[ i2 ],
7978                                                          curNodes[ i3d ],
7979                                                          curNodes[ i2t ]);
7980             myLastCreatedElems.Append(newElem);
7981             if ( aShapeId )
7982               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7983             isOk = true;
7984           }
7985           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7986                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7987             // --------------------------------------------> prism
7988             // find 2 opposite triangles
7989             nbUniqueNodes = 6;
7990             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7991               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7992                 // find indices of kept and replaced nodes
7993                 // and fill unique nodes of 2 opposite triangles
7994                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7995                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7996                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7997                 // fill unique nodes
7998                 iUnique = 0;
7999                 isOk = true;
8000                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
8001                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
8002                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
8003                   if ( n == nInit ) {
8004                     // iCur of a linked node of the opposite face (make normals co-directed):
8005                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
8006                     // check that correspondent corners of triangles are linked
8007                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
8008                       isOk = false;
8009                     else {
8010                       uniqueNodes[ iUnique ] = n;
8011                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
8012                       iUnique++;
8013                     }
8014                   }
8015                 }
8016                 break;
8017               }
8018             }
8019           }
8020         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
8021         else
8022         {
8023           MESSAGE("MergeNodes() removes hexahedron "<< elem);
8024         }
8025         break;
8026       } // HEXAHEDRON
8027
8028       default:
8029         isOk = false;
8030       } // switch ( nbNodes )
8031
8032     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
8033
8034     if ( isOk ) { // the elem remains valid after sticking nodes
8035       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
8036       {
8037         // Change nodes of polyedre
8038         const SMDS_VtkVolume* aPolyedre =
8039           dynamic_cast<const SMDS_VtkVolume*>( elem );
8040         if (aPolyedre) {
8041           int nbFaces = aPolyedre->NbFaces();
8042
8043           vector<const SMDS_MeshNode *> poly_nodes;
8044           vector<int> quantities (nbFaces);
8045
8046           for (int iface = 1; iface <= nbFaces; iface++) {
8047             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
8048             quantities[iface - 1] = nbFaceNodes;
8049
8050             for (inode = 1; inode <= nbFaceNodes; inode++) {
8051               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
8052
8053               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
8054               if (nnIt != nodeNodeMap.end()) { // curNode sticks
8055                 curNode = (*nnIt).second;
8056               }
8057               poly_nodes.push_back(curNode);
8058             }
8059           }
8060           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
8061         }
8062       }
8063       else // replace non-polyhedron elements
8064       {
8065         const SMDSAbs_ElementType etyp = elem->GetType();
8066         const int elemId               = elem->GetID();
8067         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
8068         uniqueNodes.resize(nbUniqueNodes);
8069
8070         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
8071
8072         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
8073         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
8074         if ( sm && newElem )
8075           sm->AddElement( newElem );
8076         if ( elem != newElem )
8077           ReplaceElemInGroups( elem, newElem, aMesh );
8078       }
8079     }
8080     else {
8081       // Remove invalid regular element or invalid polygon
8082       rmElemIds.push_back( elem->GetID() );
8083     }
8084
8085   } // loop on elements
8086
8087   // Remove bad elements, then equal nodes (order important)
8088
8089   Remove( rmElemIds, false );
8090   Remove( rmNodeIds, true );
8091
8092 }
8093
8094
8095 // ========================================================
8096 // class   : SortableElement
8097 // purpose : allow sorting elements basing on their nodes
8098 // ========================================================
8099 class SortableElement : public set <const SMDS_MeshElement*>
8100 {
8101 public:
8102
8103   SortableElement( const SMDS_MeshElement* theElem )
8104   {
8105     myElem = theElem;
8106     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
8107     while ( nodeIt->more() )
8108       this->insert( nodeIt->next() );
8109   }
8110
8111   const SMDS_MeshElement* Get() const
8112   { return myElem; }
8113
8114   void Set(const SMDS_MeshElement* e) const
8115   { myElem = e; }
8116
8117
8118 private:
8119   mutable const SMDS_MeshElement* myElem;
8120 };
8121
8122 //=======================================================================
8123 //function : FindEqualElements
8124 //purpose  : Return list of group of elements built on the same nodes.
8125 //           Search among theElements or in the whole mesh if theElements is empty
8126 //=======================================================================
8127 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
8128                                          TListOfListOfElementsID &      theGroupsOfElementsID)
8129 {
8130   myLastCreatedElems.Clear();
8131   myLastCreatedNodes.Clear();
8132
8133   typedef set<const SMDS_MeshElement*> TElemsSet;
8134   typedef map< SortableElement, int > TMapOfNodeSet;
8135   typedef list<int> TGroupOfElems;
8136
8137   TElemsSet elems;
8138   if ( theElements.empty() )
8139   { // get all elements in the mesh
8140     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
8141     while ( eIt->more() )
8142       elems.insert( elems.end(), eIt->next());
8143   }
8144   else
8145     elems = theElements;
8146
8147   vector< TGroupOfElems > arrayOfGroups;
8148   TGroupOfElems groupOfElems;
8149   TMapOfNodeSet mapOfNodeSet;
8150
8151   TElemsSet::iterator elemIt = elems.begin();
8152   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
8153     const SMDS_MeshElement* curElem = *elemIt;
8154     SortableElement SE(curElem);
8155     int ind = -1;
8156     // check uniqueness
8157     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
8158     if( !(pp.second) ) {
8159       TMapOfNodeSet::iterator& itSE = pp.first;
8160       ind = (*itSE).second;
8161       arrayOfGroups[ind].push_back(curElem->GetID());
8162     }
8163     else {
8164       groupOfElems.clear();
8165       groupOfElems.push_back(curElem->GetID());
8166       arrayOfGroups.push_back(groupOfElems);
8167       i++;
8168     }
8169   }
8170
8171   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
8172   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8173     groupOfElems = *groupIt;
8174     if ( groupOfElems.size() > 1 ) {
8175       groupOfElems.sort();
8176       theGroupsOfElementsID.push_back(groupOfElems);
8177     }
8178   }
8179 }
8180
8181 //=======================================================================
8182 //function : MergeElements
8183 //purpose  : In each given group, substitute all elements by the first one.
8184 //=======================================================================
8185
8186 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8187 {
8188   myLastCreatedElems.Clear();
8189   myLastCreatedNodes.Clear();
8190
8191   typedef list<int> TListOfIDs;
8192   TListOfIDs rmElemIds; // IDs of elems to remove
8193
8194   SMESHDS_Mesh* aMesh = GetMeshDS();
8195
8196   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8197   while ( groupsIt != theGroupsOfElementsID.end() ) {
8198     TListOfIDs& aGroupOfElemID = *groupsIt;
8199     aGroupOfElemID.sort();
8200     int elemIDToKeep = aGroupOfElemID.front();
8201     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8202     aGroupOfElemID.pop_front();
8203     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8204     while ( idIt != aGroupOfElemID.end() ) {
8205       int elemIDToRemove = *idIt;
8206       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8207       // add the kept element in groups of removed one (PAL15188)
8208       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8209       rmElemIds.push_back( elemIDToRemove );
8210       ++idIt;
8211     }
8212     ++groupsIt;
8213   }
8214
8215   Remove( rmElemIds, false );
8216 }
8217
8218 //=======================================================================
8219 //function : MergeEqualElements
8220 //purpose  : Remove all but one of elements built on the same nodes.
8221 //=======================================================================
8222
8223 void SMESH_MeshEditor::MergeEqualElements()
8224 {
8225   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8226                                                  to merge equal elements in the whole mesh */
8227   TListOfListOfElementsID aGroupsOfElementsID;
8228   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8229   MergeElements(aGroupsOfElementsID);
8230 }
8231
8232 //=======================================================================
8233 //function : FindFaceInSet
8234 //purpose  : Return a face having linked nodes n1 and n2 and which is
8235 //           - not in avoidSet,
8236 //           - in elemSet provided that !elemSet.empty()
8237 //           i1 and i2 optionally returns indices of n1 and n2
8238 //=======================================================================
8239
8240 const SMDS_MeshElement*
8241 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8242                                 const SMDS_MeshNode*    n2,
8243                                 const TIDSortedElemSet& elemSet,
8244                                 const TIDSortedElemSet& avoidSet,
8245                                 int*                    n1ind,
8246                                 int*                    n2ind)
8247
8248 {
8249   int i1, i2;
8250   const SMDS_MeshElement* face = 0;
8251
8252   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8253   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8254   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8255   {
8256     //MESSAGE("in while ( invElemIt->more() && !face )");
8257     const SMDS_MeshElement* elem = invElemIt->next();
8258     if (avoidSet.count( elem ))
8259       continue;
8260     if ( !elemSet.empty() && !elemSet.count( elem ))
8261       continue;
8262     // index of n1
8263     i1 = elem->GetNodeIndex( n1 );
8264     // find a n2 linked to n1
8265     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8266     for ( int di = -1; di < 2 && !face; di += 2 )
8267     {
8268       i2 = (i1+di+nbN) % nbN;
8269       if ( elem->GetNode( i2 ) == n2 )
8270         face = elem;
8271     }
8272     if ( !face && elem->IsQuadratic())
8273     {
8274       // analysis for quadratic elements using all nodes
8275       const SMDS_VtkFace* F =
8276         dynamic_cast<const SMDS_VtkFace*>(elem);
8277       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8278       // use special nodes iterator
8279       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8280       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8281       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8282       {
8283         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8284         if ( n1 == prevN && n2 == n )
8285         {
8286           face = elem;
8287         }
8288         else if ( n2 == prevN && n1 == n )
8289         {
8290           face = elem; swap( i1, i2 );
8291         }
8292         prevN = n;
8293       }
8294     }
8295   }
8296   if ( n1ind ) *n1ind = i1;
8297   if ( n2ind ) *n2ind = i2;
8298   return face;
8299 }
8300
8301 //=======================================================================
8302 //function : findAdjacentFace
8303 //purpose  :
8304 //=======================================================================
8305
8306 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8307                                                 const SMDS_MeshNode* n2,
8308                                                 const SMDS_MeshElement* elem)
8309 {
8310   TIDSortedElemSet elemSet, avoidSet;
8311   if ( elem )
8312     avoidSet.insert ( elem );
8313   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8314 }
8315
8316 //=======================================================================
8317 //function : FindFreeBorder
8318 //purpose  :
8319 //=======================================================================
8320
8321 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8322
8323 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8324                                        const SMDS_MeshNode*             theSecondNode,
8325                                        const SMDS_MeshNode*             theLastNode,
8326                                        list< const SMDS_MeshNode* > &   theNodes,
8327                                        list< const SMDS_MeshElement* >& theFaces)
8328 {
8329   if ( !theFirstNode || !theSecondNode )
8330     return false;
8331   // find border face between theFirstNode and theSecondNode
8332   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8333   if ( !curElem )
8334     return false;
8335
8336   theFaces.push_back( curElem );
8337   theNodes.push_back( theFirstNode );
8338   theNodes.push_back( theSecondNode );
8339
8340   //vector<const SMDS_MeshNode*> nodes;
8341   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8342   TIDSortedElemSet foundElems;
8343   bool needTheLast = ( theLastNode != 0 );
8344
8345   while ( nStart != theLastNode ) {
8346     if ( nStart == theFirstNode )
8347       return !needTheLast;
8348
8349     // find all free border faces sharing form nStart
8350
8351     list< const SMDS_MeshElement* > curElemList;
8352     list< const SMDS_MeshNode* > nStartList;
8353     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8354     while ( invElemIt->more() ) {
8355       const SMDS_MeshElement* e = invElemIt->next();
8356       if ( e == curElem || foundElems.insert( e ).second ) {
8357         // get nodes
8358         int iNode = 0, nbNodes = e->NbNodes();
8359         //const SMDS_MeshNode* nodes[nbNodes+1];
8360         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8361
8362         if(e->IsQuadratic()) {
8363           const SMDS_VtkFace* F =
8364             dynamic_cast<const SMDS_VtkFace*>(e);
8365           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8366           // use special nodes iterator
8367           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8368           while( anIter->more() ) {
8369             nodes[ iNode++ ] = cast2Node(anIter->next());
8370           }
8371         }
8372         else {
8373           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8374           while ( nIt->more() )
8375             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8376         }
8377         nodes[ iNode ] = nodes[ 0 ];
8378         // check 2 links
8379         for ( iNode = 0; iNode < nbNodes; iNode++ )
8380           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8381                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8382               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8383           {
8384             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8385             curElemList.push_back( e );
8386           }
8387       }
8388     }
8389     // analyse the found
8390
8391     int nbNewBorders = curElemList.size();
8392     if ( nbNewBorders == 0 ) {
8393       // no free border furthermore
8394       return !needTheLast;
8395     }
8396     else if ( nbNewBorders == 1 ) {
8397       // one more element found
8398       nIgnore = nStart;
8399       nStart = nStartList.front();
8400       curElem = curElemList.front();
8401       theFaces.push_back( curElem );
8402       theNodes.push_back( nStart );
8403     }
8404     else {
8405       // several continuations found
8406       list< const SMDS_MeshElement* >::iterator curElemIt;
8407       list< const SMDS_MeshNode* >::iterator nStartIt;
8408       // check if one of them reached the last node
8409       if ( needTheLast ) {
8410         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8411              curElemIt!= curElemList.end();
8412              curElemIt++, nStartIt++ )
8413           if ( *nStartIt == theLastNode ) {
8414             theFaces.push_back( *curElemIt );
8415             theNodes.push_back( *nStartIt );
8416             return true;
8417           }
8418       }
8419       // find the best free border by the continuations
8420       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8421       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8422       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8423            curElemIt!= curElemList.end();
8424            curElemIt++, nStartIt++ )
8425       {
8426         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8427         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8428         // find one more free border
8429         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8430           cNL->clear();
8431           cFL->clear();
8432         }
8433         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8434           // choice: clear a worse one
8435           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8436           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8437           contNodes[ iWorse ].clear();
8438           contFaces[ iWorse ].clear();
8439         }
8440       }
8441       if ( contNodes[0].empty() && contNodes[1].empty() )
8442         return false;
8443
8444       // append the best free border
8445       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8446       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8447       theNodes.pop_back(); // remove nIgnore
8448       theNodes.pop_back(); // remove nStart
8449       theFaces.pop_back(); // remove curElem
8450       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8451       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8452       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8453       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8454       return true;
8455
8456     } // several continuations found
8457   } // while ( nStart != theLastNode )
8458
8459   return true;
8460 }
8461
8462 //=======================================================================
8463 //function : CheckFreeBorderNodes
8464 //purpose  : Return true if the tree nodes are on a free border
8465 //=======================================================================
8466
8467 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8468                                             const SMDS_MeshNode* theNode2,
8469                                             const SMDS_MeshNode* theNode3)
8470 {
8471   list< const SMDS_MeshNode* > nodes;
8472   list< const SMDS_MeshElement* > faces;
8473   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8474 }
8475
8476 //=======================================================================
8477 //function : SewFreeBorder
8478 //purpose  :
8479 //=======================================================================
8480
8481 SMESH_MeshEditor::Sew_Error
8482 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8483                                  const SMDS_MeshNode* theBordSecondNode,
8484                                  const SMDS_MeshNode* theBordLastNode,
8485                                  const SMDS_MeshNode* theSideFirstNode,
8486                                  const SMDS_MeshNode* theSideSecondNode,
8487                                  const SMDS_MeshNode* theSideThirdNode,
8488                                  const bool           theSideIsFreeBorder,
8489                                  const bool           toCreatePolygons,
8490                                  const bool           toCreatePolyedrs)
8491 {
8492   myLastCreatedElems.Clear();
8493   myLastCreatedNodes.Clear();
8494
8495   MESSAGE("::SewFreeBorder()");
8496   Sew_Error aResult = SEW_OK;
8497
8498   // ====================================
8499   //    find side nodes and elements
8500   // ====================================
8501
8502   list< const SMDS_MeshNode* > nSide[ 2 ];
8503   list< const SMDS_MeshElement* > eSide[ 2 ];
8504   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8505   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8506
8507   // Free border 1
8508   // --------------
8509   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8510                       nSide[0], eSide[0])) {
8511     MESSAGE(" Free Border 1 not found " );
8512     aResult = SEW_BORDER1_NOT_FOUND;
8513   }
8514   if (theSideIsFreeBorder) {
8515     // Free border 2
8516     // --------------
8517     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8518                         nSide[1], eSide[1])) {
8519       MESSAGE(" Free Border 2 not found " );
8520       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8521     }
8522   }
8523   if ( aResult != SEW_OK )
8524     return aResult;
8525
8526   if (!theSideIsFreeBorder) {
8527     // Side 2
8528     // --------------
8529
8530     // -------------------------------------------------------------------------
8531     // Algo:
8532     // 1. If nodes to merge are not coincident, move nodes of the free border
8533     //    from the coord sys defined by the direction from the first to last
8534     //    nodes of the border to the correspondent sys of the side 2
8535     // 2. On the side 2, find the links most co-directed with the correspondent
8536     //    links of the free border
8537     // -------------------------------------------------------------------------
8538
8539     // 1. Since sewing may break if there are volumes to split on the side 2,
8540     //    we wont move nodes but just compute new coordinates for them
8541     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8542     TNodeXYZMap nBordXYZ;
8543     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8544     list< const SMDS_MeshNode* >::iterator nBordIt;
8545
8546     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8547     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8548     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8549     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8550     double tol2 = 1.e-8;
8551     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8552     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8553       // Need node movement.
8554
8555       // find X and Z axes to create trsf
8556       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8557       gp_Vec X = Zs ^ Zb;
8558       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8559         // Zb || Zs
8560         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8561
8562       // coord systems
8563       gp_Ax3 toBordAx( Pb1, Zb, X );
8564       gp_Ax3 fromSideAx( Ps1, Zs, X );
8565       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8566       // set trsf
8567       gp_Trsf toBordSys, fromSide2Sys;
8568       toBordSys.SetTransformation( toBordAx );
8569       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8570       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8571
8572       // move
8573       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8574         const SMDS_MeshNode* n = *nBordIt;
8575         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8576         toBordSys.Transforms( xyz );
8577         fromSide2Sys.Transforms( xyz );
8578         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8579       }
8580     }
8581     else {
8582       // just insert nodes XYZ in the nBordXYZ map
8583       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8584         const SMDS_MeshNode* n = *nBordIt;
8585         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8586       }
8587     }
8588
8589     // 2. On the side 2, find the links most co-directed with the correspondent
8590     //    links of the free border
8591
8592     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8593     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8594     sideNodes.push_back( theSideFirstNode );
8595
8596     bool hasVolumes = false;
8597     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8598     set<long> foundSideLinkIDs, checkedLinkIDs;
8599     SMDS_VolumeTool volume;
8600     //const SMDS_MeshNode* faceNodes[ 4 ];
8601
8602     const SMDS_MeshNode*    sideNode;
8603     const SMDS_MeshElement* sideElem;
8604     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8605     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8606     nBordIt = bordNodes.begin();
8607     nBordIt++;
8608     // border node position and border link direction to compare with
8609     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8610     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8611     // choose next side node by link direction or by closeness to
8612     // the current border node:
8613     bool searchByDir = ( *nBordIt != theBordLastNode );
8614     do {
8615       // find the next node on the Side 2
8616       sideNode = 0;
8617       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8618       long linkID;
8619       checkedLinkIDs.clear();
8620       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8621
8622       // loop on inverse elements of current node (prevSideNode) on the Side 2
8623       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8624       while ( invElemIt->more() )
8625       {
8626         const SMDS_MeshElement* elem = invElemIt->next();
8627         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8628         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8629         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8630         bool isVolume = volume.Set( elem );
8631         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8632         if ( isVolume ) // --volume
8633           hasVolumes = true;
8634         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8635           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8636           if(elem->IsQuadratic()) {
8637             const SMDS_VtkFace* F =
8638               dynamic_cast<const SMDS_VtkFace*>(elem);
8639             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8640             // use special nodes iterator
8641             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8642             while( anIter->more() ) {
8643               nodes[ iNode ] = cast2Node(anIter->next());
8644               if ( nodes[ iNode++ ] == prevSideNode )
8645                 iPrevNode = iNode - 1;
8646             }
8647           }
8648           else {
8649             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8650             while ( nIt->more() ) {
8651               nodes[ iNode ] = cast2Node( nIt->next() );
8652               if ( nodes[ iNode++ ] == prevSideNode )
8653                 iPrevNode = iNode - 1;
8654             }
8655           }
8656           // there are 2 links to check
8657           nbNodes = 2;
8658         }
8659         else // --edge
8660           continue;
8661         // loop on links, to be precise, on the second node of links
8662         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8663           const SMDS_MeshNode* n = nodes[ iNode ];
8664           if ( isVolume ) {
8665             if ( !volume.IsLinked( n, prevSideNode ))
8666               continue;
8667           }
8668           else {
8669             if ( iNode ) // a node before prevSideNode
8670               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8671             else         // a node after prevSideNode
8672               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8673           }
8674           // check if this link was already used
8675           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8676           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8677           if (!isJustChecked &&
8678               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8679           {
8680             // test a link geometrically
8681             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8682             bool linkIsBetter = false;
8683             double dot = 0.0, dist = 0.0;
8684             if ( searchByDir ) { // choose most co-directed link
8685               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8686               linkIsBetter = ( dot > maxDot );
8687             }
8688             else { // choose link with the node closest to bordPos
8689               dist = ( nextXYZ - bordPos ).SquareModulus();
8690               linkIsBetter = ( dist < minDist );
8691             }
8692             if ( linkIsBetter ) {
8693               maxDot = dot;
8694               minDist = dist;
8695               linkID = iLink;
8696               sideNode = n;
8697               sideElem = elem;
8698             }
8699           }
8700         }
8701       } // loop on inverse elements of prevSideNode
8702
8703       if ( !sideNode ) {
8704         MESSAGE(" Cant find path by links of the Side 2 ");
8705         return SEW_BAD_SIDE_NODES;
8706       }
8707       sideNodes.push_back( sideNode );
8708       sideElems.push_back( sideElem );
8709       foundSideLinkIDs.insert ( linkID );
8710       prevSideNode = sideNode;
8711
8712       if ( *nBordIt == theBordLastNode )
8713         searchByDir = false;
8714       else {
8715         // find the next border link to compare with
8716         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8717         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8718         // move to next border node if sideNode is before forward border node (bordPos)
8719         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8720           prevBordNode = *nBordIt;
8721           nBordIt++;
8722           bordPos = nBordXYZ[ *nBordIt ];
8723           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8724           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8725         }
8726       }
8727     }
8728     while ( sideNode != theSideSecondNode );
8729
8730     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8731       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8732       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8733     }
8734   } // end nodes search on the side 2
8735
8736   // ============================
8737   // sew the border to the side 2
8738   // ============================
8739
8740   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8741   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8742
8743   TListOfListOfNodes nodeGroupsToMerge;
8744   if ( nbNodes[0] == nbNodes[1] ||
8745        ( theSideIsFreeBorder && !theSideThirdNode)) {
8746
8747     // all nodes are to be merged
8748
8749     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8750          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8751          nIt[0]++, nIt[1]++ )
8752     {
8753       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8754       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8755       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8756     }
8757   }
8758   else {
8759
8760     // insert new nodes into the border and the side to get equal nb of segments
8761
8762     // get normalized parameters of nodes on the borders
8763     //double param[ 2 ][ maxNbNodes ];
8764     double* param[ 2 ];
8765     param[0] = new double [ maxNbNodes ];
8766     param[1] = new double [ maxNbNodes ];
8767     int iNode, iBord;
8768     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8769       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8770       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8771       const SMDS_MeshNode* nPrev = *nIt;
8772       double bordLength = 0;
8773       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8774         const SMDS_MeshNode* nCur = *nIt;
8775         gp_XYZ segment (nCur->X() - nPrev->X(),
8776                         nCur->Y() - nPrev->Y(),
8777                         nCur->Z() - nPrev->Z());
8778         double segmentLen = segment.Modulus();
8779         bordLength += segmentLen;
8780         param[ iBord ][ iNode ] = bordLength;
8781         nPrev = nCur;
8782       }
8783       // normalize within [0,1]
8784       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8785         param[ iBord ][ iNode ] /= bordLength;
8786       }
8787     }
8788
8789     // loop on border segments
8790     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8791     int i[ 2 ] = { 0, 0 };
8792     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8793     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8794
8795     TElemOfNodeListMap insertMap;
8796     TElemOfNodeListMap::iterator insertMapIt;
8797     // insertMap is
8798     // key:   elem to insert nodes into
8799     // value: 2 nodes to insert between + nodes to be inserted
8800     do {
8801       bool next[ 2 ] = { false, false };
8802
8803       // find min adjacent segment length after sewing
8804       double nextParam = 10., prevParam = 0;
8805       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8806         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8807           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8808         if ( i[ iBord ] > 0 )
8809           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8810       }
8811       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8812       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8813       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8814
8815       // choose to insert or to merge nodes
8816       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8817       if ( Abs( du ) <= minSegLen * 0.2 ) {
8818         // merge
8819         // ------
8820         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8821         const SMDS_MeshNode* n0 = *nIt[0];
8822         const SMDS_MeshNode* n1 = *nIt[1];
8823         nodeGroupsToMerge.back().push_back( n1 );
8824         nodeGroupsToMerge.back().push_back( n0 );
8825         // position of node of the border changes due to merge
8826         param[ 0 ][ i[0] ] += du;
8827         // move n1 for the sake of elem shape evaluation during insertion.
8828         // n1 will be removed by MergeNodes() anyway
8829         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8830         next[0] = next[1] = true;
8831       }
8832       else {
8833         // insert
8834         // ------
8835         int intoBord = ( du < 0 ) ? 0 : 1;
8836         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8837         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8838         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8839         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8840         if ( intoBord == 1 ) {
8841           // move node of the border to be on a link of elem of the side
8842           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8843           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8844           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8845           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8846           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8847         }
8848         insertMapIt = insertMap.find( elem );
8849         bool notFound = ( insertMapIt == insertMap.end() );
8850         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8851         if ( otherLink ) {
8852           // insert into another link of the same element:
8853           // 1. perform insertion into the other link of the elem
8854           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8855           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8856           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8857           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8858           // 2. perform insertion into the link of adjacent faces
8859           while (true) {
8860             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8861             if ( adjElem )
8862               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8863             else
8864               break;
8865           }
8866           if (toCreatePolyedrs) {
8867             // perform insertion into the links of adjacent volumes
8868             UpdateVolumes(n12, n22, nodeList);
8869           }
8870           // 3. find an element appeared on n1 and n2 after the insertion
8871           insertMap.erase( elem );
8872           elem = findAdjacentFace( n1, n2, 0 );
8873         }
8874         if ( notFound || otherLink ) {
8875           // add element and nodes of the side into the insertMap
8876           insertMapIt = insertMap.insert
8877             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8878           (*insertMapIt).second.push_back( n1 );
8879           (*insertMapIt).second.push_back( n2 );
8880         }
8881         // add node to be inserted into elem
8882         (*insertMapIt).second.push_back( nIns );
8883         next[ 1 - intoBord ] = true;
8884       }
8885
8886       // go to the next segment
8887       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8888         if ( next[ iBord ] ) {
8889           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8890             eIt[ iBord ]++;
8891           nPrev[ iBord ] = *nIt[ iBord ];
8892           nIt[ iBord ]++; i[ iBord ]++;
8893         }
8894       }
8895     }
8896     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8897
8898     // perform insertion of nodes into elements
8899
8900     for (insertMapIt = insertMap.begin();
8901          insertMapIt != insertMap.end();
8902          insertMapIt++ )
8903     {
8904       const SMDS_MeshElement* elem = (*insertMapIt).first;
8905       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8906       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8907       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8908
8909       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8910
8911       if ( !theSideIsFreeBorder ) {
8912         // look for and insert nodes into the faces adjacent to elem
8913         while (true) {
8914           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8915           if ( adjElem )
8916             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8917           else
8918             break;
8919         }
8920       }
8921       if (toCreatePolyedrs) {
8922         // perform insertion into the links of adjacent volumes
8923         UpdateVolumes(n1, n2, nodeList);
8924       }
8925     }
8926
8927     delete param[0];
8928     delete param[1];
8929   } // end: insert new nodes
8930
8931   MergeNodes ( nodeGroupsToMerge );
8932
8933   return aResult;
8934 }
8935
8936 //=======================================================================
8937 //function : InsertNodesIntoLink
8938 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8939 //           and theBetweenNode2 and split theElement
8940 //=======================================================================
8941
8942 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8943                                            const SMDS_MeshNode*        theBetweenNode1,
8944                                            const SMDS_MeshNode*        theBetweenNode2,
8945                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8946                                            const bool                  toCreatePoly)
8947 {
8948   if ( theFace->GetType() != SMDSAbs_Face ) return;
8949
8950   // find indices of 2 link nodes and of the rest nodes
8951   int iNode = 0, il1, il2, i3, i4;
8952   il1 = il2 = i3 = i4 = -1;
8953   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8954   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8955
8956   if(theFace->IsQuadratic()) {
8957     const SMDS_VtkFace* F =
8958       dynamic_cast<const SMDS_VtkFace*>(theFace);
8959     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8960     // use special nodes iterator
8961     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8962     while( anIter->more() ) {
8963       const SMDS_MeshNode* n = cast2Node(anIter->next());
8964       if ( n == theBetweenNode1 )
8965         il1 = iNode;
8966       else if ( n == theBetweenNode2 )
8967         il2 = iNode;
8968       else if ( i3 < 0 )
8969         i3 = iNode;
8970       else
8971         i4 = iNode;
8972       nodes[ iNode++ ] = n;
8973     }
8974   }
8975   else {
8976     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8977     while ( nodeIt->more() ) {
8978       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8979       if ( n == theBetweenNode1 )
8980         il1 = iNode;
8981       else if ( n == theBetweenNode2 )
8982         il2 = iNode;
8983       else if ( i3 < 0 )
8984         i3 = iNode;
8985       else
8986         i4 = iNode;
8987       nodes[ iNode++ ] = n;
8988     }
8989   }
8990   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8991     return ;
8992
8993   // arrange link nodes to go one after another regarding the face orientation
8994   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8995   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8996   if ( reverse ) {
8997     iNode = il1;
8998     il1 = il2;
8999     il2 = iNode;
9000     aNodesToInsert.reverse();
9001   }
9002   // check that not link nodes of a quadrangles are in good order
9003   int nbFaceNodes = theFace->NbNodes();
9004   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
9005     iNode = i3;
9006     i3 = i4;
9007     i4 = iNode;
9008   }
9009
9010   if (toCreatePoly || theFace->IsPoly()) {
9011
9012     iNode = 0;
9013     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
9014
9015     // add nodes of face up to first node of link
9016     bool isFLN = false;
9017
9018     if(theFace->IsQuadratic()) {
9019       const SMDS_VtkFace* F =
9020         dynamic_cast<const SMDS_VtkFace*>(theFace);
9021       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9022       // use special nodes iterator
9023       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9024       while( anIter->more()  && !isFLN ) {
9025         const SMDS_MeshNode* n = cast2Node(anIter->next());
9026         poly_nodes[iNode++] = n;
9027         if (n == nodes[il1]) {
9028           isFLN = true;
9029         }
9030       }
9031       // add nodes to insert
9032       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9033       for (; nIt != aNodesToInsert.end(); nIt++) {
9034         poly_nodes[iNode++] = *nIt;
9035       }
9036       // add nodes of face starting from last node of link
9037       while ( anIter->more() ) {
9038         poly_nodes[iNode++] = cast2Node(anIter->next());
9039       }
9040     }
9041     else {
9042       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
9043       while ( nodeIt->more() && !isFLN ) {
9044         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9045         poly_nodes[iNode++] = n;
9046         if (n == nodes[il1]) {
9047           isFLN = true;
9048         }
9049       }
9050       // add nodes to insert
9051       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9052       for (; nIt != aNodesToInsert.end(); nIt++) {
9053         poly_nodes[iNode++] = *nIt;
9054       }
9055       // add nodes of face starting from last node of link
9056       while ( nodeIt->more() ) {
9057         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9058         poly_nodes[iNode++] = n;
9059       }
9060     }
9061
9062     // edit or replace the face
9063     SMESHDS_Mesh *aMesh = GetMeshDS();
9064
9065     if (theFace->IsPoly()) {
9066       aMesh->ChangePolygonNodes(theFace, poly_nodes);
9067     }
9068     else {
9069       int aShapeId = FindShape( theFace );
9070
9071       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
9072       myLastCreatedElems.Append(newElem);
9073       if ( aShapeId && newElem )
9074         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9075
9076       aMesh->RemoveElement(theFace);
9077     }
9078     return;
9079   }
9080
9081   SMESHDS_Mesh *aMesh = GetMeshDS();
9082   if( !theFace->IsQuadratic() ) {
9083
9084     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
9085     int nbLinkNodes = 2 + aNodesToInsert.size();
9086     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
9087     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
9088     linkNodes[ 0 ] = nodes[ il1 ];
9089     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
9090     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9091     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9092       linkNodes[ iNode++ ] = *nIt;
9093     }
9094     // decide how to split a quadrangle: compare possible variants
9095     // and choose which of splits to be a quadrangle
9096     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
9097     if ( nbFaceNodes == 3 ) {
9098       iBestQuad = nbSplits;
9099       i4 = i3;
9100     }
9101     else if ( nbFaceNodes == 4 ) {
9102       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
9103       double aBestRate = DBL_MAX;
9104       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
9105         i1 = 0; i2 = 1;
9106         double aBadRate = 0;
9107         // evaluate elements quality
9108         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
9109           if ( iSplit == iQuad ) {
9110             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
9111                                    linkNodes[ i2++ ],
9112                                    nodes[ i3 ],
9113                                    nodes[ i4 ]);
9114             aBadRate += getBadRate( &quad, aCrit );
9115           }
9116           else {
9117             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
9118                                    linkNodes[ i2++ ],
9119                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
9120             aBadRate += getBadRate( &tria, aCrit );
9121           }
9122         }
9123         // choice
9124         if ( aBadRate < aBestRate ) {
9125           iBestQuad = iQuad;
9126           aBestRate = aBadRate;
9127         }
9128       }
9129     }
9130
9131     // create new elements
9132     int aShapeId = FindShape( theFace );
9133
9134     i1 = 0; i2 = 1;
9135     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
9136       SMDS_MeshElement* newElem = 0;
9137       if ( iSplit == iBestQuad )
9138         newElem = aMesh->AddFace (linkNodes[ i1++ ],
9139                                   linkNodes[ i2++ ],
9140                                   nodes[ i3 ],
9141                                   nodes[ i4 ]);
9142       else
9143         newElem = aMesh->AddFace (linkNodes[ i1++ ],
9144                                   linkNodes[ i2++ ],
9145                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
9146       myLastCreatedElems.Append(newElem);
9147       if ( aShapeId && newElem )
9148         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9149     }
9150
9151     // change nodes of theFace
9152     const SMDS_MeshNode* newNodes[ 4 ];
9153     newNodes[ 0 ] = linkNodes[ i1 ];
9154     newNodes[ 1 ] = linkNodes[ i2 ];
9155     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
9156     newNodes[ 3 ] = nodes[ i4 ];
9157     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
9158     const SMDS_MeshElement* newElem = 0;
9159     if (iSplit == iBestQuad)
9160       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
9161     else
9162       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
9163     myLastCreatedElems.Append(newElem);
9164     if ( aShapeId && newElem )
9165       aMesh->SetMeshElementOnShape( newElem, aShapeId );
9166 } // end if(!theFace->IsQuadratic())
9167   else { // theFace is quadratic
9168     // we have to split theFace on simple triangles and one simple quadrangle
9169     int tmp = il1/2;
9170     int nbshift = tmp*2;
9171     // shift nodes in nodes[] by nbshift
9172     int i,j;
9173     for(i=0; i<nbshift; i++) {
9174       const SMDS_MeshNode* n = nodes[0];
9175       for(j=0; j<nbFaceNodes-1; j++) {
9176         nodes[j] = nodes[j+1];
9177       }
9178       nodes[nbFaceNodes-1] = n;
9179     }
9180     il1 = il1 - nbshift;
9181     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9182     //   n0      n1     n2    n0      n1     n2
9183     //     +-----+-----+        +-----+-----+
9184     //      \         /         |           |
9185     //       \       /          |           |
9186     //      n5+     +n3       n7+           +n3
9187     //         \   /            |           |
9188     //          \ /             |           |
9189     //           +              +-----+-----+
9190     //           n4           n6      n5     n4
9191
9192     // create new elements
9193     int aShapeId = FindShape( theFace );
9194
9195     int n1,n2,n3;
9196     if(nbFaceNodes==6) { // quadratic triangle
9197       SMDS_MeshElement* newElem =
9198         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9199       myLastCreatedElems.Append(newElem);
9200       if ( aShapeId && newElem )
9201         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9202       if(theFace->IsMediumNode(nodes[il1])) {
9203         // create quadrangle
9204         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9205         myLastCreatedElems.Append(newElem);
9206         if ( aShapeId && newElem )
9207           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9208         n1 = 1;
9209         n2 = 2;
9210         n3 = 3;
9211       }
9212       else {
9213         // create quadrangle
9214         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9215         myLastCreatedElems.Append(newElem);
9216         if ( aShapeId && newElem )
9217           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9218         n1 = 0;
9219         n2 = 1;
9220         n3 = 5;
9221       }
9222     }
9223     else { // nbFaceNodes==8 - quadratic quadrangle
9224       SMDS_MeshElement* newElem =
9225         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9226       myLastCreatedElems.Append(newElem);
9227       if ( aShapeId && newElem )
9228         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9229       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9230       myLastCreatedElems.Append(newElem);
9231       if ( aShapeId && newElem )
9232         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9233       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9234       myLastCreatedElems.Append(newElem);
9235       if ( aShapeId && newElem )
9236         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9237       if(theFace->IsMediumNode(nodes[il1])) {
9238         // create quadrangle
9239         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9240         myLastCreatedElems.Append(newElem);
9241         if ( aShapeId && newElem )
9242           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9243         n1 = 1;
9244         n2 = 2;
9245         n3 = 3;
9246       }
9247       else {
9248         // create quadrangle
9249         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9250         myLastCreatedElems.Append(newElem);
9251         if ( aShapeId && newElem )
9252           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9253         n1 = 0;
9254         n2 = 1;
9255         n3 = 7;
9256       }
9257     }
9258     // create needed triangles using n1,n2,n3 and inserted nodes
9259     int nbn = 2 + aNodesToInsert.size();
9260     //const SMDS_MeshNode* aNodes[nbn];
9261     vector<const SMDS_MeshNode*> aNodes(nbn);
9262     aNodes[0] = nodes[n1];
9263     aNodes[nbn-1] = nodes[n2];
9264     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9265     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9266       aNodes[iNode++] = *nIt;
9267     }
9268     for(i=1; i<nbn; i++) {
9269       SMDS_MeshElement* newElem =
9270         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9271       myLastCreatedElems.Append(newElem);
9272       if ( aShapeId && newElem )
9273         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9274     }
9275   }
9276   // remove old face
9277   aMesh->RemoveElement(theFace);
9278 }
9279
9280 //=======================================================================
9281 //function : UpdateVolumes
9282 //purpose  :
9283 //=======================================================================
9284 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9285                                       const SMDS_MeshNode*        theBetweenNode2,
9286                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9287 {
9288   myLastCreatedElems.Clear();
9289   myLastCreatedNodes.Clear();
9290
9291   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9292   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9293     const SMDS_MeshElement* elem = invElemIt->next();
9294
9295     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9296     SMDS_VolumeTool aVolume (elem);
9297     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9298       continue;
9299
9300     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9301     int iface, nbFaces = aVolume.NbFaces();
9302     vector<const SMDS_MeshNode *> poly_nodes;
9303     vector<int> quantities (nbFaces);
9304
9305     for (iface = 0; iface < nbFaces; iface++) {
9306       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9307       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9308       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9309
9310       for (int inode = 0; inode < nbFaceNodes; inode++) {
9311         poly_nodes.push_back(faceNodes[inode]);
9312
9313         if (nbInserted == 0) {
9314           if (faceNodes[inode] == theBetweenNode1) {
9315             if (faceNodes[inode + 1] == theBetweenNode2) {
9316               nbInserted = theNodesToInsert.size();
9317
9318               // add nodes to insert
9319               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9320               for (; nIt != theNodesToInsert.end(); nIt++) {
9321                 poly_nodes.push_back(*nIt);
9322               }
9323             }
9324           }
9325           else if (faceNodes[inode] == theBetweenNode2) {
9326             if (faceNodes[inode + 1] == theBetweenNode1) {
9327               nbInserted = theNodesToInsert.size();
9328
9329               // add nodes to insert in reversed order
9330               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9331               nIt--;
9332               for (; nIt != theNodesToInsert.begin(); nIt--) {
9333                 poly_nodes.push_back(*nIt);
9334               }
9335               poly_nodes.push_back(*nIt);
9336             }
9337           }
9338           else {
9339           }
9340         }
9341       }
9342       quantities[iface] = nbFaceNodes + nbInserted;
9343     }
9344
9345     // Replace or update the volume
9346     SMESHDS_Mesh *aMesh = GetMeshDS();
9347
9348     if (elem->IsPoly()) {
9349       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9350
9351     }
9352     else {
9353       int aShapeId = FindShape( elem );
9354
9355       SMDS_MeshElement* newElem =
9356         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9357       myLastCreatedElems.Append(newElem);
9358       if (aShapeId && newElem)
9359         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9360
9361       aMesh->RemoveElement(elem);
9362     }
9363   }
9364 }
9365
9366 //=======================================================================
9367 /*!
9368  * \brief Convert elements contained in a submesh to quadratic
9369  * \return int - nb of checked elements
9370  */
9371 //=======================================================================
9372
9373 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9374                                              SMESH_MesherHelper& theHelper,
9375                                              const bool          theForce3d)
9376 {
9377   int nbElem = 0;
9378   if( !theSm ) return nbElem;
9379
9380   vector<int> nbNodeInFaces;
9381   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9382   while(ElemItr->more())
9383   {
9384     nbElem++;
9385     const SMDS_MeshElement* elem = ElemItr->next();
9386     if( !elem || elem->IsQuadratic() ) continue;
9387
9388     int id = elem->GetID();
9389     int nbNodes = elem->NbNodes();
9390     SMDSAbs_ElementType aType = elem->GetType();
9391
9392     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9393     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9394       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9395
9396     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9397
9398     const SMDS_MeshElement* NewElem = 0;
9399
9400     switch( aType )
9401     {
9402     case SMDSAbs_Edge :
9403       {
9404         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9405         break;
9406       }
9407     case SMDSAbs_Face :
9408       {
9409         switch(nbNodes)
9410         {
9411         case 3:
9412           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9413           break;
9414         case 4:
9415           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9416           break;
9417         default:
9418           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9419           continue;
9420         }
9421         break;
9422       }
9423     case SMDSAbs_Volume :
9424       {
9425         switch(nbNodes)
9426         {
9427         case 4:
9428           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9429           break;
9430         case 5:
9431           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9432           break;
9433         case 6:
9434           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9435           break;
9436         case 8:
9437           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9438                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9439           break;
9440         default:
9441           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9442         }
9443         break;
9444       }
9445     default :
9446       continue;
9447     }
9448     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9449     if( NewElem )
9450       theSm->AddElement( NewElem );
9451   }
9452 //  if (!GetMeshDS()->isCompacted())
9453 //    GetMeshDS()->compactMesh();
9454   return nbElem;
9455 }
9456
9457 //=======================================================================
9458 //function : ConvertToQuadratic
9459 //purpose  :
9460 //=======================================================================
9461 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9462 {
9463   SMESHDS_Mesh* meshDS = GetMeshDS();
9464
9465   SMESH_MesherHelper aHelper(*myMesh);
9466   aHelper.SetIsQuadratic( true );
9467
9468   int nbCheckedElems = 0;
9469   if ( myMesh->HasShapeToMesh() )
9470   {
9471     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9472     {
9473       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9474       while ( smIt->more() ) {
9475         SMESH_subMesh* sm = smIt->next();
9476         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9477           aHelper.SetSubShape( sm->GetSubShape() );
9478           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9479         }
9480       }
9481     }
9482   }
9483   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9484   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9485   {
9486     SMESHDS_SubMesh *smDS = 0;
9487     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9488     while(aEdgeItr->more())
9489     {
9490       const SMDS_MeshEdge* edge = aEdgeItr->next();
9491       if(edge && !edge->IsQuadratic())
9492       {
9493         int id = edge->GetID();
9494         //MESSAGE("edge->GetID() " << id);
9495         const SMDS_MeshNode* n1 = edge->GetNode(0);
9496         const SMDS_MeshNode* n2 = edge->GetNode(1);
9497
9498         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9499
9500         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9501         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9502       }
9503     }
9504     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9505     while(aFaceItr->more())
9506     {
9507       const SMDS_MeshFace* face = aFaceItr->next();
9508       if(!face || face->IsQuadratic() ) continue;
9509
9510       int id = face->GetID();
9511       int nbNodes = face->NbNodes();
9512       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9513
9514       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9515
9516       SMDS_MeshFace * NewFace = 0;
9517       switch(nbNodes)
9518       {
9519       case 3:
9520         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9521         break;
9522       case 4:
9523         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9524         break;
9525       default:
9526         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9527       }
9528       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9529     }
9530     vector<int> nbNodeInFaces;
9531     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9532     while(aVolumeItr->more())
9533     {
9534       const SMDS_MeshVolume* volume = aVolumeItr->next();
9535       if(!volume || volume->IsQuadratic() ) continue;
9536
9537       int id = volume->GetID();
9538       int nbNodes = volume->NbNodes();
9539       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9540       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9541         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9542
9543       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9544
9545       SMDS_MeshVolume * NewVolume = 0;
9546       switch(nbNodes)
9547       {
9548       case 4:
9549         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9550                                       nodes[3], id, theForce3d );
9551         break;
9552       case 5:
9553         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9554                                       nodes[3], nodes[4], id, theForce3d);
9555         break;
9556       case 6:
9557         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9558                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9559         break;
9560       case 8:
9561         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9562                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9563         break;
9564       default:
9565         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9566       }
9567       ReplaceElemInGroups(volume, NewVolume, meshDS);
9568     }
9569   }
9570
9571   if ( !theForce3d )
9572   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9573     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9574     aHelper.FixQuadraticElements();
9575   }
9576 }
9577
9578 //================================================================================
9579 /*!
9580  * \brief Makes given elements quadratic
9581  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9582  *  \param theElements - elements to make quadratic 
9583  */
9584 //================================================================================
9585
9586 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9587                                           TIDSortedElemSet& theElements)
9588 {
9589   if ( theElements.empty() ) return;
9590
9591   // we believe that all theElements are of the same type
9592   SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9593   
9594   // get all nodes shared by theElements
9595   TIDSortedNodeSet allNodes;
9596   TIDSortedElemSet::iterator eIt = theElements.begin();
9597   for ( ; eIt != theElements.end(); ++eIt )
9598     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9599
9600   // complete theElements with elements of lower dim whose all nodes are in allNodes
9601
9602   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9603   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9604   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9605   for ( ; nIt != allNodes.end(); ++nIt )
9606   {
9607     const SMDS_MeshNode* n = *nIt;
9608     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9609     while ( invIt->more() )
9610     {
9611       const SMDS_MeshElement* e = invIt->next();
9612       if ( e->IsQuadratic() )
9613       {
9614         quadAdjacentElems[ e->GetType() ].insert( e );
9615         continue;
9616       }
9617       if ( e->GetType() >= elemType )
9618       {
9619         continue; // same type of more complex linear element
9620       }
9621
9622       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9623         continue; // e is already checked
9624
9625       // check nodes
9626       bool allIn = true;
9627       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9628       while ( nodeIt->more() && allIn )
9629         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9630       if ( allIn )
9631         theElements.insert(e );
9632     }
9633   }
9634
9635   SMESH_MesherHelper helper(*myMesh);
9636   helper.SetIsQuadratic( true );
9637
9638   // add links of quadratic adjacent elements to the helper
9639
9640   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9641     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9642           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9643     {
9644       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9645     }
9646   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9647     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9648           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9649     {
9650       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9651     }
9652   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9653     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9654           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9655     {
9656       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9657     }
9658
9659   // make quadratic elements instead of linear ones
9660
9661   SMESHDS_Mesh* meshDS = GetMeshDS();
9662   SMESHDS_SubMesh* smDS = 0;
9663   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9664   {
9665     const SMDS_MeshElement* elem = *eIt;
9666     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9667       continue;
9668
9669     int id = elem->GetID();
9670     SMDSAbs_ElementType type = elem->GetType();
9671     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9672
9673     if ( !smDS || !smDS->Contains( elem ))
9674       smDS = meshDS->MeshElements( elem->getshapeId() );
9675     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9676
9677     SMDS_MeshElement * newElem = 0;
9678     switch( nodes.size() )
9679     {
9680     case 4: // cases for most multiple element types go first (for optimization)
9681       if ( type == SMDSAbs_Volume )
9682         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9683       else
9684         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9685       break;
9686     case 8:
9687       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9688                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9689       break;
9690     case 3:
9691       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9692       break;
9693     case 2:
9694       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9695       break;
9696     case 5:
9697       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9698                                  nodes[4], id, theForce3d);
9699       break;
9700     case 6:
9701       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9702                                  nodes[4], nodes[5], id, theForce3d);
9703       break;
9704     default:;
9705     }
9706     ReplaceElemInGroups( elem, newElem, meshDS);
9707     if( newElem && smDS )
9708       smDS->AddElement( newElem );
9709   }
9710
9711   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9712   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9713     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9714     helper.FixQuadraticElements();
9715   }
9716 }
9717
9718 //=======================================================================
9719 /*!
9720  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9721  * \return int - nb of checked elements
9722  */
9723 //=======================================================================
9724
9725 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9726                                      SMDS_ElemIteratorPtr theItr,
9727                                      const int            theShapeID)
9728 {
9729   int nbElem = 0;
9730   SMESHDS_Mesh* meshDS = GetMeshDS();
9731
9732   while( theItr->more() )
9733   {
9734     const SMDS_MeshElement* elem = theItr->next();
9735     nbElem++;
9736     if( elem && elem->IsQuadratic())
9737     {
9738       int id                    = elem->GetID();
9739       int nbCornerNodes         = elem->NbCornerNodes();
9740       SMDSAbs_ElementType aType = elem->GetType();
9741
9742       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9743
9744       //remove a quadratic element
9745       if ( !theSm || !theSm->Contains( elem ))
9746         theSm = meshDS->MeshElements( elem->getshapeId() );
9747       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9748
9749       // remove medium nodes
9750       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9751         if ( nodes[i]->NbInverseElements() == 0 )
9752           meshDS->RemoveFreeNode( nodes[i], theSm );
9753
9754       // add a linear element
9755       nodes.resize( nbCornerNodes );
9756       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9757       ReplaceElemInGroups(elem, newElem, meshDS);
9758       if( theSm && newElem )
9759         theSm->AddElement( newElem );
9760     }
9761   }
9762   return nbElem;
9763 }
9764
9765 //=======================================================================
9766 //function : ConvertFromQuadratic
9767 //purpose  :
9768 //=======================================================================
9769
9770 bool SMESH_MeshEditor::ConvertFromQuadratic()
9771 {
9772   int nbCheckedElems = 0;
9773   if ( myMesh->HasShapeToMesh() )
9774   {
9775     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9776     {
9777       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9778       while ( smIt->more() ) {
9779         SMESH_subMesh* sm = smIt->next();
9780         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9781           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9782       }
9783     }
9784   }
9785
9786   int totalNbElems =
9787     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9788   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9789   {
9790     SMESHDS_SubMesh *aSM = 0;
9791     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9792   }
9793
9794   return true;
9795 }
9796
9797 namespace
9798 {
9799   //================================================================================
9800   /*!
9801    * \brief Return true if all medium nodes of the element are in the node set
9802    */
9803   //================================================================================
9804
9805   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9806   {
9807     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9808       if ( !nodeSet.count( elem->GetNode(i) ))
9809         return false;
9810     return true;
9811   }
9812 }
9813
9814 //================================================================================
9815 /*!
9816  * \brief Makes given elements linear
9817  */
9818 //================================================================================
9819
9820 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9821 {
9822   if ( theElements.empty() ) return;
9823
9824   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9825   set<int> mediumNodeIDs;
9826   TIDSortedElemSet::iterator eIt = theElements.begin();
9827   for ( ; eIt != theElements.end(); ++eIt )
9828   {
9829     const SMDS_MeshElement* e = *eIt;
9830     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9831       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9832   }
9833
9834   // replace given elements by linear ones
9835   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9836   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9837   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9838
9839   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9840   // except those elements sharing medium nodes of quadratic element whose medium nodes
9841   // are not all in mediumNodeIDs
9842
9843   // get remaining medium nodes
9844   TIDSortedNodeSet mediumNodes;
9845   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9846   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9847     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9848       mediumNodes.insert( mediumNodes.end(), n );
9849
9850   // find more quadratic elements to convert
9851   TIDSortedElemSet moreElemsToConvert;
9852   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9853   for ( ; nIt != mediumNodes.end(); ++nIt )
9854   {
9855     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9856     while ( invIt->more() )
9857     {
9858       const SMDS_MeshElement* e = invIt->next();
9859       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9860       {
9861         // find a more complex element including e and
9862         // whose medium nodes are not in mediumNodes
9863         bool complexFound = false;
9864         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9865         {
9866           SMDS_ElemIteratorPtr invIt2 =
9867             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9868           while ( invIt2->more() )
9869           {
9870             const SMDS_MeshElement* eComplex = invIt2->next();
9871             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9872             {
9873               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9874               if ( nbCommonNodes == e->NbNodes())
9875               {
9876                 complexFound = true;
9877                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9878                 break;
9879               }
9880             }
9881           }
9882         }
9883         if ( !complexFound )
9884           moreElemsToConvert.insert( e );
9885       }
9886     }
9887   }
9888   elemIt = SMDS_ElemIteratorPtr
9889     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9890   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9891 }
9892
9893 //=======================================================================
9894 //function : SewSideElements
9895 //purpose  :
9896 //=======================================================================
9897
9898 SMESH_MeshEditor::Sew_Error
9899 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9900                                    TIDSortedElemSet&    theSide2,
9901                                    const SMDS_MeshNode* theFirstNode1,
9902                                    const SMDS_MeshNode* theFirstNode2,
9903                                    const SMDS_MeshNode* theSecondNode1,
9904                                    const SMDS_MeshNode* theSecondNode2)
9905 {
9906   myLastCreatedElems.Clear();
9907   myLastCreatedNodes.Clear();
9908
9909   MESSAGE ("::::SewSideElements()");
9910   if ( theSide1.size() != theSide2.size() )
9911     return SEW_DIFF_NB_OF_ELEMENTS;
9912
9913   Sew_Error aResult = SEW_OK;
9914   // Algo:
9915   // 1. Build set of faces representing each side
9916   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9917   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9918
9919   // =======================================================================
9920   // 1. Build set of faces representing each side:
9921   // =======================================================================
9922   // a. build set of nodes belonging to faces
9923   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9924   // c. create temporary faces representing side of volumes if correspondent
9925   //    face does not exist
9926
9927   SMESHDS_Mesh* aMesh = GetMeshDS();
9928   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9929   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9930   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9931   set<const SMDS_MeshElement*> volSet1,  volSet2;
9932   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9933   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9934   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9935   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9936   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9937   int iSide, iFace, iNode;
9938
9939   list<const SMDS_MeshElement* > tempFaceList;
9940   for ( iSide = 0; iSide < 2; iSide++ ) {
9941     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9942     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9943     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9944     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9945     set<const SMDS_MeshElement*>::iterator vIt;
9946     TIDSortedElemSet::iterator eIt;
9947     set<const SMDS_MeshNode*>::iterator    nIt;
9948
9949     // check that given nodes belong to given elements
9950     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9951     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9952     int firstIndex = -1, secondIndex = -1;
9953     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9954       const SMDS_MeshElement* elem = *eIt;
9955       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9956       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9957       if ( firstIndex > -1 && secondIndex > -1 ) break;
9958     }
9959     if ( firstIndex < 0 || secondIndex < 0 ) {
9960       // we can simply return until temporary faces created
9961       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9962     }
9963
9964     // -----------------------------------------------------------
9965     // 1a. Collect nodes of existing faces
9966     //     and build set of face nodes in order to detect missing
9967     //     faces corresponding to sides of volumes
9968     // -----------------------------------------------------------
9969
9970     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9971
9972     // loop on the given element of a side
9973     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9974       //const SMDS_MeshElement* elem = *eIt;
9975       const SMDS_MeshElement* elem = *eIt;
9976       if ( elem->GetType() == SMDSAbs_Face ) {
9977         faceSet->insert( elem );
9978         set <const SMDS_MeshNode*> faceNodeSet;
9979         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9980         while ( nodeIt->more() ) {
9981           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9982           nodeSet->insert( n );
9983           faceNodeSet.insert( n );
9984         }
9985         setOfFaceNodeSet.insert( faceNodeSet );
9986       }
9987       else if ( elem->GetType() == SMDSAbs_Volume )
9988         volSet->insert( elem );
9989     }
9990     // ------------------------------------------------------------------------------
9991     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9992     // ------------------------------------------------------------------------------
9993
9994     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9995       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9996       while ( fIt->more() ) { // loop on faces sharing a node
9997         const SMDS_MeshElement* f = fIt->next();
9998         if ( faceSet->find( f ) == faceSet->end() ) {
9999           // check if all nodes are in nodeSet and
10000           // complete setOfFaceNodeSet if they are
10001           set <const SMDS_MeshNode*> faceNodeSet;
10002           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10003           bool allInSet = true;
10004           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10005             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10006             if ( nodeSet->find( n ) == nodeSet->end() )
10007               allInSet = false;
10008             else
10009               faceNodeSet.insert( n );
10010           }
10011           if ( allInSet ) {
10012             faceSet->insert( f );
10013             setOfFaceNodeSet.insert( faceNodeSet );
10014           }
10015         }
10016       }
10017     }
10018
10019     // -------------------------------------------------------------------------
10020     // 1c. Create temporary faces representing sides of volumes if correspondent
10021     //     face does not exist
10022     // -------------------------------------------------------------------------
10023
10024     if ( !volSet->empty() ) {
10025       //int nodeSetSize = nodeSet->size();
10026
10027       // loop on given volumes
10028       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
10029         SMDS_VolumeTool vol (*vIt);
10030         // loop on volume faces: find free faces
10031         // --------------------------------------
10032         list<const SMDS_MeshElement* > freeFaceList;
10033         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
10034           if ( !vol.IsFreeFace( iFace ))
10035             continue;
10036           // check if there is already a face with same nodes in a face set
10037           const SMDS_MeshElement* aFreeFace = 0;
10038           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
10039           int nbNodes = vol.NbFaceNodes( iFace );
10040           set <const SMDS_MeshNode*> faceNodeSet;
10041           vol.GetFaceNodes( iFace, faceNodeSet );
10042           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
10043           if ( isNewFace ) {
10044             // no such a face is given but it still can exist, check it
10045             if ( nbNodes == 3 ) {
10046               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
10047             }
10048             else if ( nbNodes == 4 ) {
10049               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10050             }
10051             else {
10052               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
10053               aFreeFace = aMesh->FindFace(poly_nodes);
10054             }
10055           }
10056           if ( !aFreeFace ) {
10057             // create a temporary face
10058             if ( nbNodes == 3 ) {
10059               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
10060               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
10061             }
10062             else if ( nbNodes == 4 ) {
10063               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10064               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10065             }
10066             else {
10067               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
10068               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
10069               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
10070             }
10071           }
10072           if ( aFreeFace ) {
10073             freeFaceList.push_back( aFreeFace );
10074             tempFaceList.push_back( aFreeFace );
10075           }
10076
10077         } // loop on faces of a volume
10078
10079         // choose one of several free faces
10080         // --------------------------------------
10081         if ( freeFaceList.size() > 1 ) {
10082           // choose a face having max nb of nodes shared by other elems of a side
10083           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
10084           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
10085           while ( fIt != freeFaceList.end() ) { // loop on free faces
10086             int nbSharedNodes = 0;
10087             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
10088             while ( nodeIt->more() ) { // loop on free face nodes
10089               const SMDS_MeshNode* n =
10090                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10091               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
10092               while ( invElemIt->more() ) {
10093                 const SMDS_MeshElement* e = invElemIt->next();
10094                 if ( faceSet->find( e ) != faceSet->end() )
10095                   nbSharedNodes++;
10096                 if ( elemSet->find( e ) != elemSet->end() )
10097                   nbSharedNodes++;
10098               }
10099             }
10100             if ( nbSharedNodes >= maxNbNodes ) {
10101               maxNbNodes = nbSharedNodes;
10102               fIt++;
10103             }
10104             else
10105               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
10106           }
10107           if ( freeFaceList.size() > 1 )
10108           {
10109             // could not choose one face, use another way
10110             // choose a face most close to the bary center of the opposite side
10111             gp_XYZ aBC( 0., 0., 0. );
10112             set <const SMDS_MeshNode*> addedNodes;
10113             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
10114             eIt = elemSet2->begin();
10115             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
10116               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
10117               while ( nodeIt->more() ) { // loop on free face nodes
10118                 const SMDS_MeshNode* n =
10119                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10120                 if ( addedNodes.insert( n ).second )
10121                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
10122               }
10123             }
10124             aBC /= addedNodes.size();
10125             double minDist = DBL_MAX;
10126             fIt = freeFaceList.begin();
10127             while ( fIt != freeFaceList.end() ) { // loop on free faces
10128               double dist = 0;
10129               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
10130               while ( nodeIt->more() ) { // loop on free face nodes
10131                 const SMDS_MeshNode* n =
10132                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10133                 gp_XYZ p( n->X(),n->Y(),n->Z() );
10134                 dist += ( aBC - p ).SquareModulus();
10135               }
10136               if ( dist < minDist ) {
10137                 minDist = dist;
10138                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
10139               }
10140               else
10141                 fIt = freeFaceList.erase( fIt++ );
10142             }
10143           }
10144         } // choose one of several free faces of a volume
10145
10146         if ( freeFaceList.size() == 1 ) {
10147           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
10148           faceSet->insert( aFreeFace );
10149           // complete a node set with nodes of a found free face
10150           //           for ( iNode = 0; iNode < ; iNode++ )
10151           //             nodeSet->insert( fNodes[ iNode ] );
10152         }
10153
10154       } // loop on volumes of a side
10155
10156       //       // complete a set of faces if new nodes in a nodeSet appeared
10157       //       // ----------------------------------------------------------
10158       //       if ( nodeSetSize != nodeSet->size() ) {
10159       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10160       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10161       //           while ( fIt->more() ) { // loop on faces sharing a node
10162       //             const SMDS_MeshElement* f = fIt->next();
10163       //             if ( faceSet->find( f ) == faceSet->end() ) {
10164       //               // check if all nodes are in nodeSet and
10165       //               // complete setOfFaceNodeSet if they are
10166       //               set <const SMDS_MeshNode*> faceNodeSet;
10167       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10168       //               bool allInSet = true;
10169       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10170       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10171       //                 if ( nodeSet->find( n ) == nodeSet->end() )
10172       //                   allInSet = false;
10173       //                 else
10174       //                   faceNodeSet.insert( n );
10175       //               }
10176       //               if ( allInSet ) {
10177       //                 faceSet->insert( f );
10178       //                 setOfFaceNodeSet.insert( faceNodeSet );
10179       //               }
10180       //             }
10181       //           }
10182       //         }
10183       //       }
10184     } // Create temporary faces, if there are volumes given
10185   } // loop on sides
10186
10187   if ( faceSet1.size() != faceSet2.size() ) {
10188     // delete temporary faces: they are in reverseElements of actual nodes
10189 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10190 //    while ( tmpFaceIt->more() )
10191 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10192 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10193 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10194 //      aMesh->RemoveElement(*tmpFaceIt);
10195     MESSAGE("Diff nb of faces");
10196     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10197   }
10198
10199   // ============================================================
10200   // 2. Find nodes to merge:
10201   //              bind a node to remove to a node to put instead
10202   // ============================================================
10203
10204   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10205   if ( theFirstNode1 != theFirstNode2 )
10206     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10207   if ( theSecondNode1 != theSecondNode2 )
10208     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10209
10210   LinkID_Gen aLinkID_Gen( GetMeshDS() );
10211   set< long > linkIdSet; // links to process
10212   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10213
10214   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10215   list< NLink > linkList[2];
10216   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10217   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10218   // loop on links in linkList; find faces by links and append links
10219   // of the found faces to linkList
10220   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10221   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10222     NLink link[] = { *linkIt[0], *linkIt[1] };
10223     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10224     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10225       continue;
10226
10227     // by links, find faces in the face sets,
10228     // and find indices of link nodes in the found faces;
10229     // in a face set, there is only one or no face sharing a link
10230     // ---------------------------------------------------------------
10231
10232     const SMDS_MeshElement* face[] = { 0, 0 };
10233     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10234     vector<const SMDS_MeshNode*> fnodes1(9);
10235     vector<const SMDS_MeshNode*> fnodes2(9);
10236     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10237     vector<const SMDS_MeshNode*> notLinkNodes1(6);
10238     vector<const SMDS_MeshNode*> notLinkNodes2(6);
10239     int iLinkNode[2][2];
10240     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10241       const SMDS_MeshNode* n1 = link[iSide].first;
10242       const SMDS_MeshNode* n2 = link[iSide].second;
10243       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10244       set< const SMDS_MeshElement* > fMap;
10245       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10246         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10247         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10248         while ( fIt->more() ) { // loop on faces sharing a node
10249           const SMDS_MeshElement* f = fIt->next();
10250           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10251               ! fMap.insert( f ).second ) // f encounters twice
10252           {
10253             if ( face[ iSide ] ) {
10254               MESSAGE( "2 faces per link " );
10255               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10256               break;
10257             }
10258             face[ iSide ] = f;
10259             faceSet->erase( f );
10260             // get face nodes and find ones of a link
10261             iNode = 0;
10262             int nbl = -1;
10263             if(f->IsPoly()) {
10264               if(iSide==0) {
10265                 fnodes1.resize(f->NbNodes()+1);
10266                 notLinkNodes1.resize(f->NbNodes()-2);
10267               }
10268               else {
10269                 fnodes2.resize(f->NbNodes()+1);
10270                 notLinkNodes2.resize(f->NbNodes()-2);
10271               }
10272             }
10273             if(!f->IsQuadratic()) {
10274               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10275               while ( nIt->more() ) {
10276                 const SMDS_MeshNode* n =
10277                   static_cast<const SMDS_MeshNode*>( nIt->next() );
10278                 if ( n == n1 ) {
10279                   iLinkNode[ iSide ][ 0 ] = iNode;
10280                 }
10281                 else if ( n == n2 ) {
10282                   iLinkNode[ iSide ][ 1 ] = iNode;
10283                 }
10284                 //else if ( notLinkNodes[ iSide ][ 0 ] )
10285                 //  notLinkNodes[ iSide ][ 1 ] = n;
10286                 //else
10287                 //  notLinkNodes[ iSide ][ 0 ] = n;
10288                 else {
10289                   nbl++;
10290                   if(iSide==0)
10291                     notLinkNodes1[nbl] = n;
10292                   //notLinkNodes1.push_back(n);
10293                   else
10294                     notLinkNodes2[nbl] = n;
10295                   //notLinkNodes2.push_back(n);
10296                 }
10297                 //faceNodes[ iSide ][ iNode++ ] = n;
10298                 if(iSide==0) {
10299                   fnodes1[iNode++] = n;
10300                 }
10301                 else {
10302                   fnodes2[iNode++] = n;
10303                 }
10304               }
10305             }
10306             else { // f->IsQuadratic()
10307               const SMDS_VtkFace* F =
10308                 dynamic_cast<const SMDS_VtkFace*>(f);
10309               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10310               // use special nodes iterator
10311               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10312               while ( anIter->more() ) {
10313                 const SMDS_MeshNode* n =
10314                   static_cast<const SMDS_MeshNode*>( anIter->next() );
10315                 if ( n == n1 ) {
10316                   iLinkNode[ iSide ][ 0 ] = iNode;
10317                 }
10318                 else if ( n == n2 ) {
10319                   iLinkNode[ iSide ][ 1 ] = iNode;
10320                 }
10321                 else {
10322                   nbl++;
10323                   if(iSide==0) {
10324                     notLinkNodes1[nbl] = n;
10325                   }
10326                   else {
10327                     notLinkNodes2[nbl] = n;
10328                   }
10329                 }
10330                 if(iSide==0) {
10331                   fnodes1[iNode++] = n;
10332                 }
10333                 else {
10334                   fnodes2[iNode++] = n;
10335                 }
10336               }
10337             }
10338             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10339             if(iSide==0) {
10340               fnodes1[iNode] = fnodes1[0];
10341             }
10342             else {
10343               fnodes2[iNode] = fnodes1[0];
10344             }
10345           }
10346         }
10347       }
10348     }
10349
10350     // check similarity of elements of the sides
10351     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10352       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10353       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10354         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10355       }
10356       else {
10357         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10358       }
10359       break; // do not return because it s necessary to remove tmp faces
10360     }
10361
10362     // set nodes to merge
10363     // -------------------
10364
10365     if ( face[0] && face[1] )  {
10366       int nbNodes = face[0]->NbNodes();
10367       if ( nbNodes != face[1]->NbNodes() ) {
10368         MESSAGE("Diff nb of face nodes");
10369         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10370         break; // do not return because it s necessary to remove tmp faces
10371       }
10372       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10373       if ( nbNodes == 3 ) {
10374         //nReplaceMap.insert( TNodeNodeMap::value_type
10375         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10376         nReplaceMap.insert( TNodeNodeMap::value_type
10377                             ( notLinkNodes1[0], notLinkNodes2[0] ));
10378       }
10379       else {
10380         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10381           // analyse link orientation in faces
10382           int i1 = iLinkNode[ iSide ][ 0 ];
10383           int i2 = iLinkNode[ iSide ][ 1 ];
10384           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10385           // if notLinkNodes are the first and the last ones, then
10386           // their order does not correspond to the link orientation
10387           if (( i1 == 1 && i2 == 2 ) ||
10388               ( i1 == 2 && i2 == 1 ))
10389             reverse[ iSide ] = !reverse[ iSide ];
10390         }
10391         if ( reverse[0] == reverse[1] ) {
10392           //nReplaceMap.insert( TNodeNodeMap::value_type
10393           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10394           //nReplaceMap.insert( TNodeNodeMap::value_type
10395           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10396           for(int nn=0; nn<nbNodes-2; nn++) {
10397             nReplaceMap.insert( TNodeNodeMap::value_type
10398                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10399           }
10400         }
10401         else {
10402           //nReplaceMap.insert( TNodeNodeMap::value_type
10403           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10404           //nReplaceMap.insert( TNodeNodeMap::value_type
10405           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10406           for(int nn=0; nn<nbNodes-2; nn++) {
10407             nReplaceMap.insert( TNodeNodeMap::value_type
10408                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10409           }
10410         }
10411       }
10412
10413       // add other links of the faces to linkList
10414       // -----------------------------------------
10415
10416       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10417       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10418         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10419         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10420         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10421         if ( !iter_isnew.second ) { // already in a set: no need to process
10422           linkIdSet.erase( iter_isnew.first );
10423         }
10424         else // new in set == encountered for the first time: add
10425         {
10426           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10427           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10428           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10429           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10430           linkList[0].push_back ( NLink( n1, n2 ));
10431           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10432         }
10433       }
10434     } // 2 faces found
10435   } // loop on link lists
10436
10437   if ( aResult == SEW_OK &&
10438        ( linkIt[0] != linkList[0].end() ||
10439          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10440     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10441              " " << (faceSetPtr[1]->empty()));
10442     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10443   }
10444
10445   // ====================================================================
10446   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10447   // ====================================================================
10448
10449   // delete temporary faces: they are in reverseElements of actual nodes
10450 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10451 //  while ( tmpFaceIt->more() )
10452 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10453 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10454 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10455 //    aMesh->RemoveElement(*tmpFaceIt);
10456
10457   if ( aResult != SEW_OK)
10458     return aResult;
10459
10460   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10461   // loop on nodes replacement map
10462   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10463   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10464     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10465       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10466       nodeIDsToRemove.push_back( nToRemove->GetID() );
10467       // loop on elements sharing nToRemove
10468       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10469       while ( invElemIt->more() ) {
10470         const SMDS_MeshElement* e = invElemIt->next();
10471         // get a new suite of nodes: make replacement
10472         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10473         vector< const SMDS_MeshNode*> nodes( nbNodes );
10474         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10475         while ( nIt->more() ) {
10476           const SMDS_MeshNode* n =
10477             static_cast<const SMDS_MeshNode*>( nIt->next() );
10478           nnIt = nReplaceMap.find( n );
10479           if ( nnIt != nReplaceMap.end() ) {
10480             nbReplaced++;
10481             n = (*nnIt).second;
10482           }
10483           nodes[ i++ ] = n;
10484         }
10485         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10486         //         elemIDsToRemove.push_back( e->GetID() );
10487         //       else
10488         if ( nbReplaced )
10489           {
10490             SMDSAbs_ElementType etyp = e->GetType();
10491             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10492             if (newElem)
10493               {
10494                 myLastCreatedElems.Append(newElem);
10495                 AddToSameGroups(newElem, e, aMesh);
10496                 int aShapeId = e->getshapeId();
10497                 if ( aShapeId )
10498                   {
10499                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10500                   }
10501               }
10502             aMesh->RemoveElement(e);
10503           }
10504       }
10505     }
10506
10507   Remove( nodeIDsToRemove, true );
10508
10509   return aResult;
10510 }
10511
10512 //================================================================================
10513 /*!
10514  * \brief Find corresponding nodes in two sets of faces
10515  * \param theSide1 - first face set
10516  * \param theSide2 - second first face
10517  * \param theFirstNode1 - a boundary node of set 1
10518  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10519  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10520  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10521  * \param nReplaceMap - output map of corresponding nodes
10522  * \return bool  - is a success or not
10523  */
10524 //================================================================================
10525
10526 #ifdef _DEBUG_
10527 //#define DEBUG_MATCHING_NODES
10528 #endif
10529
10530 SMESH_MeshEditor::Sew_Error
10531 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10532                                     set<const SMDS_MeshElement*>& theSide2,
10533                                     const SMDS_MeshNode*          theFirstNode1,
10534                                     const SMDS_MeshNode*          theFirstNode2,
10535                                     const SMDS_MeshNode*          theSecondNode1,
10536                                     const SMDS_MeshNode*          theSecondNode2,
10537                                     TNodeNodeMap &                nReplaceMap)
10538 {
10539   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10540
10541   nReplaceMap.clear();
10542   if ( theFirstNode1 != theFirstNode2 )
10543     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10544   if ( theSecondNode1 != theSecondNode2 )
10545     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10546
10547   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10548   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10549
10550   list< NLink > linkList[2];
10551   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10552   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10553
10554   // loop on links in linkList; find faces by links and append links
10555   // of the found faces to linkList
10556   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10557   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10558     NLink link[] = { *linkIt[0], *linkIt[1] };
10559     if ( linkSet.find( link[0] ) == linkSet.end() )
10560       continue;
10561
10562     // by links, find faces in the face sets,
10563     // and find indices of link nodes in the found faces;
10564     // in a face set, there is only one or no face sharing a link
10565     // ---------------------------------------------------------------
10566
10567     const SMDS_MeshElement* face[] = { 0, 0 };
10568     list<const SMDS_MeshNode*> notLinkNodes[2];
10569     //bool reverse[] = { false, false }; // order of notLinkNodes
10570     int nbNodes[2];
10571     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10572     {
10573       const SMDS_MeshNode* n1 = link[iSide].first;
10574       const SMDS_MeshNode* n2 = link[iSide].second;
10575       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10576       set< const SMDS_MeshElement* > facesOfNode1;
10577       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10578       {
10579         // during a loop of the first node, we find all faces around n1,
10580         // during a loop of the second node, we find one face sharing both n1 and n2
10581         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10582         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10583         while ( fIt->more() ) { // loop on faces sharing a node
10584           const SMDS_MeshElement* f = fIt->next();
10585           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10586               ! facesOfNode1.insert( f ).second ) // f encounters twice
10587           {
10588             if ( face[ iSide ] ) {
10589               MESSAGE( "2 faces per link " );
10590               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10591             }
10592             face[ iSide ] = f;
10593             faceSet->erase( f );
10594
10595             // get not link nodes
10596             int nbN = f->NbNodes();
10597             if ( f->IsQuadratic() )
10598               nbN /= 2;
10599             nbNodes[ iSide ] = nbN;
10600             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10601             int i1 = f->GetNodeIndex( n1 );
10602             int i2 = f->GetNodeIndex( n2 );
10603             int iEnd = nbN, iBeg = -1, iDelta = 1;
10604             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10605             if ( reverse ) {
10606               std::swap( iEnd, iBeg ); iDelta = -1;
10607             }
10608             int i = i2;
10609             while ( true ) {
10610               i += iDelta;
10611               if ( i == iEnd ) i = iBeg + iDelta;
10612               if ( i == i1 ) break;
10613               nodes.push_back ( f->GetNode( i ) );
10614             }
10615           }
10616         }
10617       }
10618     }
10619     // check similarity of elements of the sides
10620     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10621       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10622       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10623         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10624       }
10625       else {
10626         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10627       }
10628     }
10629
10630     // set nodes to merge
10631     // -------------------
10632
10633     if ( face[0] && face[1] )  {
10634       if ( nbNodes[0] != nbNodes[1] ) {
10635         MESSAGE("Diff nb of face nodes");
10636         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10637       }
10638 #ifdef DEBUG_MATCHING_NODES
10639       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10640                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10641                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10642 #endif
10643       int nbN = nbNodes[0];
10644       {
10645         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10646         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10647         for ( int i = 0 ; i < nbN - 2; ++i ) {
10648 #ifdef DEBUG_MATCHING_NODES
10649           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10650 #endif
10651           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10652         }
10653       }
10654
10655       // add other links of the face 1 to linkList
10656       // -----------------------------------------
10657
10658       const SMDS_MeshElement* f0 = face[0];
10659       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10660       for ( int i = 0; i < nbN; i++ )
10661       {
10662         const SMDS_MeshNode* n2 = f0->GetNode( i );
10663         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10664           linkSet.insert( SMESH_TLink( n1, n2 ));
10665         if ( !iter_isnew.second ) { // already in a set: no need to process
10666           linkSet.erase( iter_isnew.first );
10667         }
10668         else // new in set == encountered for the first time: add
10669         {
10670 #ifdef DEBUG_MATCHING_NODES
10671           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10672                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10673 #endif
10674           linkList[0].push_back ( NLink( n1, n2 ));
10675           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10676         }
10677         n1 = n2;
10678       }
10679     } // 2 faces found
10680   } // loop on link lists
10681
10682   return SEW_OK;
10683 }
10684
10685 //================================================================================
10686 /*!
10687   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10688   \param theElems - the list of elements (edges or faces) to be replicated
10689   The nodes for duplication could be found from these elements
10690   \param theNodesNot - list of nodes to NOT replicate
10691   \param theAffectedElems - the list of elements (cells and edges) to which the 
10692   replicated nodes should be associated to.
10693   \return TRUE if operation has been completed successfully, FALSE otherwise
10694 */
10695 //================================================================================
10696
10697 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10698                                     const TIDSortedElemSet& theNodesNot,
10699                                     const TIDSortedElemSet& theAffectedElems )
10700 {
10701   myLastCreatedElems.Clear();
10702   myLastCreatedNodes.Clear();
10703
10704   if ( theElems.size() == 0 )
10705     return false;
10706
10707   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10708   if ( !aMeshDS )
10709     return false;
10710
10711   bool res = false;
10712   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10713   // duplicate elements and nodes
10714   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10715   // replce nodes by duplications
10716   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10717   return res;
10718 }
10719
10720 //================================================================================
10721 /*!
10722   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10723   \param theMeshDS - mesh instance
10724   \param theElems - the elements replicated or modified (nodes should be changed)
10725   \param theNodesNot - nodes to NOT replicate
10726   \param theNodeNodeMap - relation of old node to new created node
10727   \param theIsDoubleElem - flag os to replicate element or modify
10728   \return TRUE if operation has been completed successfully, FALSE otherwise
10729 */
10730 //================================================================================
10731
10732 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10733                                     const TIDSortedElemSet& theElems,
10734                                     const TIDSortedElemSet& theNodesNot,
10735                                     std::map< const SMDS_MeshNode*,
10736                                     const SMDS_MeshNode* >& theNodeNodeMap,
10737                                     const bool theIsDoubleElem )
10738 {
10739   MESSAGE("doubleNodes");
10740   // iterate on through element and duplicate them (by nodes duplication)
10741   bool res = false;
10742   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10743   for ( ;  elemItr != theElems.end(); ++elemItr )
10744   {
10745     const SMDS_MeshElement* anElem = *elemItr;
10746     if (!anElem)
10747       continue;
10748
10749     bool isDuplicate = false;
10750     // duplicate nodes to duplicate element
10751     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10752     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10753     int ind = 0;
10754     while ( anIter->more() ) 
10755     { 
10756
10757       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10758       SMDS_MeshNode* aNewNode = aCurrNode;
10759       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10760         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10761       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10762       {
10763         // duplicate node
10764         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10765         theNodeNodeMap[ aCurrNode ] = aNewNode;
10766         myLastCreatedNodes.Append( aNewNode );
10767       }
10768       isDuplicate |= (aCurrNode != aNewNode);
10769       newNodes[ ind++ ] = aNewNode;
10770     }
10771     if ( !isDuplicate )
10772       continue;
10773
10774     if ( theIsDoubleElem )
10775       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10776     else
10777       {
10778       MESSAGE("ChangeElementNodes");
10779       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10780       }
10781     res = true;
10782   }
10783   return res;
10784 }
10785
10786 //================================================================================
10787 /*!
10788   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10789   \param theNodes - identifiers of nodes to be doubled
10790   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10791          nodes. If list of element identifiers is empty then nodes are doubled but 
10792          they not assigned to elements
10793   \return TRUE if operation has been completed successfully, FALSE otherwise
10794 */
10795 //================================================================================
10796
10797 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10798                                     const std::list< int >& theListOfModifiedElems )
10799 {
10800   MESSAGE("DoubleNodes");
10801   myLastCreatedElems.Clear();
10802   myLastCreatedNodes.Clear();
10803
10804   if ( theListOfNodes.size() == 0 )
10805     return false;
10806
10807   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10808   if ( !aMeshDS )
10809     return false;
10810
10811   // iterate through nodes and duplicate them
10812
10813   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10814
10815   std::list< int >::const_iterator aNodeIter;
10816   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10817   {
10818     int aCurr = *aNodeIter;
10819     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10820     if ( !aNode )
10821       continue;
10822
10823     // duplicate node
10824
10825     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10826     if ( aNewNode )
10827     {
10828       anOldNodeToNewNode[ aNode ] = aNewNode;
10829       myLastCreatedNodes.Append( aNewNode );
10830     }
10831   }
10832
10833   // Create map of new nodes for modified elements
10834
10835   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10836
10837   std::list< int >::const_iterator anElemIter;
10838   for ( anElemIter = theListOfModifiedElems.begin(); 
10839         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10840   {
10841     int aCurr = *anElemIter;
10842     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10843     if ( !anElem )
10844       continue;
10845
10846     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10847
10848     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10849     int ind = 0;
10850     while ( anIter->more() ) 
10851     { 
10852       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10853       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10854       {
10855         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10856         aNodeArr[ ind++ ] = aNewNode;
10857       }
10858       else
10859         aNodeArr[ ind++ ] = aCurrNode;
10860     }
10861     anElemToNodes[ anElem ] = aNodeArr;
10862   }
10863
10864   // Change nodes of elements  
10865
10866   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10867     anElemToNodesIter = anElemToNodes.begin();
10868   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10869   {
10870     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10871     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10872     if ( anElem )
10873       {
10874       MESSAGE("ChangeElementNodes");
10875       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10876       }
10877   }
10878
10879   return true;
10880 }
10881
10882 namespace {
10883
10884   //================================================================================
10885   /*!
10886   \brief Check if element located inside shape
10887   \return TRUE if IN or ON shape, FALSE otherwise
10888   */
10889   //================================================================================
10890
10891   template<class Classifier>
10892   bool isInside(const SMDS_MeshElement* theElem,
10893                 Classifier&             theClassifier,
10894                 const double            theTol)
10895   {
10896     gp_XYZ centerXYZ (0, 0, 0);
10897     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10898     while (aNodeItr->more())
10899       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10900
10901     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10902     theClassifier.Perform(aPnt, theTol);
10903     TopAbs_State aState = theClassifier.State();
10904     return (aState == TopAbs_IN || aState == TopAbs_ON );
10905   }
10906
10907   //================================================================================
10908   /*!
10909    * \brief Classifier of the 3D point on the TopoDS_Face
10910    *        with interaface suitable for isInside()
10911    */
10912   //================================================================================
10913
10914   struct _FaceClassifier
10915   {
10916     Extrema_ExtPS       _extremum;
10917     BRepAdaptor_Surface _surface;
10918     TopAbs_State        _state;
10919
10920     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10921     {
10922       _extremum.Initialize( _surface,
10923                             _surface.FirstUParameter(), _surface.LastUParameter(),
10924                             _surface.FirstVParameter(), _surface.LastVParameter(),
10925                             _surface.Tolerance(), _surface.Tolerance() );
10926     }
10927     void Perform(const gp_Pnt& aPnt, double theTol)
10928     {
10929       _state = TopAbs_OUT;
10930       _extremum.Perform(aPnt);
10931       if ( _extremum.IsDone() )
10932         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10933 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
10934           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10935 #else
10936           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10937 #endif
10938     }
10939     TopAbs_State State() const
10940     {
10941       return _state;
10942     }
10943   };
10944 }
10945
10946 //================================================================================
10947 /*!
10948   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10949   \param theElems - group of of elements (edges or faces) to be replicated
10950   \param theNodesNot - group of nodes not to replicate
10951   \param theShape - shape to detect affected elements (element which geometric center
10952   located on or inside shape).
10953   The replicated nodes should be associated to affected elements.
10954   \return TRUE if operation has been completed successfully, FALSE otherwise
10955 */
10956 //================================================================================
10957
10958 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10959                                             const TIDSortedElemSet& theNodesNot,
10960                                             const TopoDS_Shape&     theShape )
10961 {
10962   if ( theShape.IsNull() )
10963     return false;
10964
10965   const double aTol = Precision::Confusion();
10966   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10967   auto_ptr<_FaceClassifier>              aFaceClassifier;
10968   if ( theShape.ShapeType() == TopAbs_SOLID )
10969   {
10970     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10971     bsc3d->PerformInfinitePoint(aTol);
10972   }
10973   else if (theShape.ShapeType() == TopAbs_FACE )
10974   {
10975     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10976   }
10977
10978   // iterates on indicated elements and get elements by back references from their nodes
10979   TIDSortedElemSet anAffected;
10980   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10981   for ( ;  elemItr != theElems.end(); ++elemItr )
10982   {
10983     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10984     if (!anElem)
10985       continue;
10986
10987     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10988     while ( nodeItr->more() )
10989     {
10990       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10991       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10992         continue;
10993       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10994       while ( backElemItr->more() )
10995       {
10996         const SMDS_MeshElement* curElem = backElemItr->next();
10997         if ( curElem && theElems.find(curElem) == theElems.end() &&
10998              ( bsc3d.get() ?
10999                isInside( curElem, *bsc3d, aTol ) :
11000                isInside( curElem, *aFaceClassifier, aTol )))
11001           anAffected.insert( curElem );
11002       }
11003     }
11004   }
11005   return DoubleNodes( theElems, theNodesNot, anAffected );
11006 }
11007
11008 /*!
11009  *  \brief compute an oriented angle between two planes defined by four points.
11010  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
11011  *  @param p0 base of the rotation axe
11012  *  @param p1 extremity of the rotation axe
11013  *  @param g1 belongs to the first plane
11014  *  @param g2 belongs to the second plane
11015  */
11016 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
11017 {
11018 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
11019 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
11020 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
11021 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
11022   gp_Vec vref(p0, p1);
11023   gp_Vec v1(p0, g1);
11024   gp_Vec v2(p0, g2);
11025   gp_Vec n1 = vref.Crossed(v1);
11026   gp_Vec n2 = vref.Crossed(v2);
11027   return n2.AngleWithRef(n1, vref);
11028 }
11029
11030 /*!
11031  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
11032  * The list of groups must describe a partition of the mesh volumes.
11033  * The nodes of the internal faces at the boundaries of the groups are doubled.
11034  * In option, the internal faces are replaced by flat elements.
11035  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11036  * The flat elements are stored in groups of volumes.
11037  * @param theElems - list of groups of volumes, where a group of volume is a set of
11038  * SMDS_MeshElements sorted by Id.
11039  * @param createJointElems - if TRUE, create the elements
11040  * @return TRUE if operation has been completed successfully, FALSE otherwise
11041  */
11042 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
11043                                                      bool createJointElems)
11044 {
11045   MESSAGE("----------------------------------------------");
11046   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
11047   MESSAGE("----------------------------------------------");
11048
11049   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11050   meshDS->BuildDownWardConnectivity(true);
11051   CHRONO(50);
11052   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
11053
11054   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
11055   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
11056   //     build the list of nodes shared by 2 or more domains, with their domain indexes
11057
11058   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
11059   std::map<int,int>celldom; // cell vtkId --> domain
11060   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
11061   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
11062   faceDomains.clear();
11063   celldom.clear();
11064   cellDomains.clear();
11065   nodeDomains.clear();
11066   std::map<int,int> emptyMap;
11067   std::set<int> emptySet;
11068   emptyMap.clear();
11069
11070   for (int idom = 0; idom < theElems.size(); idom++)
11071     {
11072
11073       // --- build a map (face to duplicate --> volume to modify)
11074       //     with all the faces shared by 2 domains (group of elements)
11075       //     and corresponding volume of this domain, for each shared face.
11076       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
11077
11078       const TIDSortedElemSet& domain = theElems[idom];
11079       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11080       for (; elemItr != domain.end(); ++elemItr)
11081         {
11082           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11083           if (!anElem)
11084             continue;
11085           int vtkId = anElem->getVtkId();
11086           int neighborsVtkIds[NBMAXNEIGHBORS];
11087           int downIds[NBMAXNEIGHBORS];
11088           unsigned char downTypes[NBMAXNEIGHBORS];
11089           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11090           for (int n = 0; n < nbNeighbors; n++)
11091             {
11092               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
11093               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11094               if (! domain.count(elem)) // neighbor is in another domain : face is shared
11095                 {
11096                   DownIdType face(downIds[n], downTypes[n]);
11097                   if (!faceDomains.count(face))
11098                     faceDomains[face] = emptyMap; // create an empty entry for face
11099                   if (!faceDomains[face].count(idom))
11100                     {
11101                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
11102                       celldom[vtkId] = idom;
11103                     }
11104                 }
11105             }
11106         }
11107     }
11108
11109   //MESSAGE("Number of shared faces " << faceDomains.size());
11110   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
11111
11112   // --- explore the shared faces domain by domain,
11113   //     explore the nodes of the face and see if they belong to a cell in the domain,
11114   //     which has only a node or an edge on the border (not a shared face)
11115
11116   for (int idomain = 0; idomain < theElems.size(); idomain++)
11117     {
11118       const TIDSortedElemSet& domain = theElems[idomain];
11119       itface = faceDomains.begin();
11120       for (; itface != faceDomains.end(); ++itface)
11121         {
11122           std::map<int, int> domvol = itface->second;
11123           if (!domvol.count(idomain))
11124             continue;
11125           DownIdType face = itface->first;
11126           //MESSAGE(" --- face " << face.cellId);
11127           std::set<int> oldNodes;
11128           oldNodes.clear();
11129           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11130           std::set<int>::iterator itn = oldNodes.begin();
11131           for (; itn != oldNodes.end(); ++itn)
11132             {
11133               int oldId = *itn;
11134               //MESSAGE("     node " << oldId);
11135               std::set<int> cells;
11136               cells.clear();
11137               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11138               for (int i=0; i<l.ncells; i++)
11139                 {
11140                   int vtkId = l.cells[i];
11141                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
11142                   if (!domain.count(anElem))
11143                     continue;
11144                   int vtkType = grid->GetCellType(vtkId);
11145                   int downId = grid->CellIdToDownId(vtkId);
11146                   if (downId < 0)
11147                     {
11148                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
11149                       continue; // not OK at this stage of the algorithm:
11150                                 //no cells created after BuildDownWardConnectivity
11151                     }
11152                   DownIdType aCell(downId, vtkType);
11153                   if (celldom.count(vtkId))
11154                     continue;
11155                   cellDomains[aCell][idomain] = vtkId;
11156                   celldom[vtkId] = idomain;
11157                 }
11158             }
11159         }
11160     }
11161
11162   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
11163   //     for each shared face, get the nodes
11164   //     for each node, for each domain of the face, create a clone of the node
11165
11166   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
11167   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
11168   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
11169
11170   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
11171   std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
11172
11173   for (int idomain = 0; idomain < theElems.size(); idomain++)
11174     {
11175       itface = faceDomains.begin();
11176       for (; itface != faceDomains.end(); ++itface)
11177         {
11178           std::map<int, int> domvol = itface->second;
11179           if (!domvol.count(idomain))
11180             continue;
11181           DownIdType face = itface->first;
11182           //MESSAGE(" --- face " << face.cellId);
11183           std::set<int> oldNodes;
11184           oldNodes.clear();
11185           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11186           bool isMultipleDetected = false;
11187           std::set<int>::iterator itn = oldNodes.begin();
11188           for (; itn != oldNodes.end(); ++itn)
11189             {
11190               int oldId = *itn;
11191               //MESSAGE("     node " << oldId);
11192               if (!nodeDomains.count(oldId))
11193                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11194               if (nodeDomains[oldId].empty())
11195                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11196               std::map<int, int>::iterator itdom = domvol.begin();
11197               for (; itdom != domvol.end(); ++itdom)
11198                 {
11199                   int idom = itdom->first;
11200                   //MESSAGE("         domain " << idom);
11201                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
11202                     {
11203                       if (nodeDomains[oldId].size() >= 2) // a multiple node
11204                         {
11205                           vector<int> orderedDoms;
11206                           //MESSAGE("multiple node " << oldId);
11207                           isMultipleDetected =true;
11208                           if (mutipleNodes.count(oldId))
11209                             orderedDoms = mutipleNodes[oldId];
11210                           else
11211                             {
11212                               map<int,int>::iterator it = nodeDomains[oldId].begin();
11213                               for (; it != nodeDomains[oldId].end(); ++it)
11214                                 orderedDoms.push_back(it->first);
11215                             }
11216                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
11217                           //stringstream txt;
11218                           //for (int i=0; i<orderedDoms.size(); i++)
11219                           //  txt << orderedDoms[i] << " ";
11220                           //MESSAGE("orderedDoms " << txt.str());
11221                           mutipleNodes[oldId] = orderedDoms;
11222                         }
11223                       double *coords = grid->GetPoint(oldId);
11224                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11225                       int newId = newNode->getVtkId();
11226                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
11227                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11228                     }
11229                   if (nodeDomains[oldId].size() >= 3)
11230                     {
11231                       //MESSAGE("confirm multiple node " << oldId);
11232                       isMultipleDetected =true;
11233                     }
11234                 }
11235             }
11236           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11237             {
11238               //MESSAGE("multiple Nodes detected on a shared face");
11239               int downId = itface->first.cellId;
11240               unsigned char cellType = itface->first.cellType;
11241               int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11242               const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11243               const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11244               for (int ie =0; ie < nbEdges; ie++)
11245                 {
11246                   int nodes[3];
11247                   int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11248                   if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11249                     {
11250                       vector<int> vn0 = mutipleNodes[nodes[0]];
11251                       vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11252                       sort( vn0.begin(), vn0.end() );
11253                       sort( vn1.begin(), vn1.end() );
11254                       if (vn0 == vn1)
11255                         {
11256                           //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11257                           double *coords = grid->GetPoint(nodes[0]);
11258                           gp_Pnt p0(coords[0], coords[1], coords[2]);
11259                           coords = grid->GetPoint(nodes[nbNodes - 1]);
11260                           gp_Pnt p1(coords[0], coords[1], coords[2]);
11261                           gp_Pnt gref;
11262                           int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11263                           map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11264                           map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11265                           int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11266                           for (int id=0; id < vn0.size(); id++)
11267                             {
11268                               int idom = vn0[id];
11269                               for (int ivol=0; ivol<nbvol; ivol++)
11270                                 {
11271                                   int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11272                                   SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11273                                   if (theElems[idom].count(elem))
11274                                     {
11275                                       SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11276                                       domvol[idom] = svol;
11277                                       //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11278                                       double values[3];
11279                                       vtkIdType npts = 0;
11280                                       vtkIdType* pts = 0;
11281                                       grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11282                                       SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11283                                       if (id ==0)
11284                                         {
11285                                           gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11286                                           angleDom[idom] = 0;
11287                                         }
11288                                       else
11289                                         {
11290                                           gp_Pnt g(values[0], values[1], values[2]);
11291                                           angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11292                                           //MESSAGE("  angle=" << angleDom[idom]);
11293                                         }
11294                                       break;
11295                                     }
11296                                 }
11297                             }
11298                           map<double, int> sortedDom; // sort domains by angle
11299                           for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11300                             sortedDom[ia->second] = ia->first;
11301                           vector<int> vnodes;
11302                           vector<int> vdom;
11303                           for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11304                             {
11305                               vdom.push_back(ib->second);
11306                               //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11307                             }
11308                           for (int ino = 0; ino < nbNodes; ino++)
11309                             vnodes.push_back(nodes[ino]);
11310                           edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11311                         }
11312                     }
11313                 }
11314             }
11315         }
11316     }
11317
11318   // --- iterate on shared faces (volumes to modify, face to extrude)
11319   //     get node id's of the face (id SMDS = id VTK)
11320   //     create flat element with old and new nodes if requested
11321
11322   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11323   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11324
11325   std::map<int, std::map<long,int> > nodeQuadDomains;
11326   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11327
11328   if (createJointElems)
11329     {
11330       itface = faceDomains.begin();
11331       for (; itface != faceDomains.end(); ++itface)
11332         {
11333           DownIdType face = itface->first;
11334           std::set<int> oldNodes;
11335           std::set<int>::iterator itn;
11336           oldNodes.clear();
11337           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11338
11339           std::map<int, int> domvol = itface->second;
11340           std::map<int, int>::iterator itdom = domvol.begin();
11341           int dom1 = itdom->first;
11342           int vtkVolId = itdom->second;
11343           itdom++;
11344           int dom2 = itdom->first;
11345           SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11346                                                              nodeQuadDomains);
11347           stringstream grpname;
11348           grpname << "j_";
11349           if (dom1 < dom2)
11350             grpname << dom1 << "_" << dom2;
11351           else
11352             grpname << dom2 << "_" << dom1;
11353           int idg;
11354           string namegrp = grpname.str();
11355           if (!mapOfJunctionGroups.count(namegrp))
11356             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11357           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11358           if (sgrp)
11359             sgrp->Add(vol->GetID());
11360         }
11361     }
11362
11363   // --- create volumes on multiple domain intersection if requested
11364   //     iterate on edgesMultiDomains
11365
11366   if (createJointElems)
11367     {
11368       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11369       for (; ite != edgesMultiDomains.end(); ++ite)
11370         {
11371           vector<int> nodes = ite->first;
11372           vector<int> orderDom = ite->second;
11373           vector<vtkIdType> orderedNodes;
11374           if (nodes.size() == 2)
11375             {
11376               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11377               for (int ino=0; ino < nodes.size(); ino++)
11378                 if (orderDom.size() == 3)
11379                   for (int idom = 0; idom <orderDom.size(); idom++)
11380                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11381                 else
11382                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11383                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11384               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11385
11386               stringstream grpname;
11387               grpname << "mj_";
11388               grpname << 0 << "_" << 0;
11389               int idg;
11390               string namegrp = grpname.str();
11391               if (!mapOfJunctionGroups.count(namegrp))
11392                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11393               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11394               if (sgrp)
11395                 sgrp->Add(vol->GetID());
11396             }
11397           else
11398             {
11399               //MESSAGE("Quadratic multiple joints not implemented");
11400               // TODO quadratic nodes
11401             }
11402         }
11403     }
11404
11405   // --- list the explicit faces and edges of the mesh that need to be modified,
11406   //     i.e. faces and edges built with one or more duplicated nodes.
11407   //     associate these faces or edges to their corresponding domain.
11408   //     only the first domain found is kept when a face or edge is shared
11409
11410   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11411   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11412   faceOrEdgeDom.clear();
11413   feDom.clear();
11414
11415   for (int idomain = 0; idomain < theElems.size(); idomain++)
11416     {
11417       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11418       for (; itnod != nodeDomains.end(); ++itnod)
11419         {
11420           int oldId = itnod->first;
11421           //MESSAGE("     node " << oldId);
11422           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11423           for (int i = 0; i < l.ncells; i++)
11424             {
11425               int vtkId = l.cells[i];
11426               int vtkType = grid->GetCellType(vtkId);
11427               int downId = grid->CellIdToDownId(vtkId);
11428               if (downId < 0)
11429                 continue; // new cells: not to be modified
11430               DownIdType aCell(downId, vtkType);
11431               int volParents[1000];
11432               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11433               for (int j = 0; j < nbvol; j++)
11434                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11435                   if (!feDom.count(vtkId))
11436                     {
11437                       feDom[vtkId] = idomain;
11438                       faceOrEdgeDom[aCell] = emptyMap;
11439                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11440                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11441                       //        << " type " << vtkType << " downId " << downId);
11442                     }
11443             }
11444         }
11445     }
11446
11447   // --- iterate on shared faces (volumes to modify, face to extrude)
11448   //     get node id's of the face
11449   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11450
11451   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11452   for (int m=0; m<3; m++)
11453     {
11454       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11455       itface = (*amap).begin();
11456       for (; itface != (*amap).end(); ++itface)
11457         {
11458           DownIdType face = itface->first;
11459           std::set<int> oldNodes;
11460           std::set<int>::iterator itn;
11461           oldNodes.clear();
11462           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11463           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11464           std::map<int, int> localClonedNodeIds;
11465
11466           std::map<int, int> domvol = itface->second;
11467           std::map<int, int>::iterator itdom = domvol.begin();
11468           for (; itdom != domvol.end(); ++itdom)
11469             {
11470               int idom = itdom->first;
11471               int vtkVolId = itdom->second;
11472               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11473               localClonedNodeIds.clear();
11474               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11475                 {
11476                   int oldId = *itn;
11477                   if (nodeDomains[oldId].count(idom))
11478                     {
11479                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11480                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11481                     }
11482                 }
11483               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11484             }
11485         }
11486     }
11487
11488   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11489   grid->BuildLinks();
11490
11491   CHRONOSTOP(50);
11492   counters::stats();
11493   return true;
11494 }
11495
11496 /*!
11497  * \brief Double nodes on some external faces and create flat elements.
11498  * Flat elements are mainly used by some types of mechanic calculations.
11499  *
11500  * Each group of the list must be constituted of faces.
11501  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11502  * @param theElems - list of groups of faces, where a group of faces is a set of
11503  * SMDS_MeshElements sorted by Id.
11504  * @return TRUE if operation has been completed successfully, FALSE otherwise
11505  */
11506 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11507 {
11508   MESSAGE("-------------------------------------------------");
11509   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11510   MESSAGE("-------------------------------------------------");
11511
11512   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11513
11514   // --- For each group of faces
11515   //     duplicate the nodes, create a flat element based on the face
11516   //     replace the nodes of the faces by their clones
11517
11518   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11519   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11520   clonedNodes.clear();
11521   intermediateNodes.clear();
11522   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11523   mapOfJunctionGroups.clear();
11524
11525   for (int idom = 0; idom < theElems.size(); idom++)
11526     {
11527       const TIDSortedElemSet& domain = theElems[idom];
11528       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11529       for (; elemItr != domain.end(); ++elemItr)
11530         {
11531           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11532           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11533           if (!aFace)
11534             continue;
11535           // MESSAGE("aFace=" << aFace->GetID());
11536           bool isQuad = aFace->IsQuadratic();
11537           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11538
11539           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11540
11541           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11542           while (nodeIt->more())
11543             {
11544               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11545               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11546               if (isMedium)
11547                 ln2.push_back(node);
11548               else
11549                 ln0.push_back(node);
11550
11551               const SMDS_MeshNode* clone = 0;
11552               if (!clonedNodes.count(node))
11553                 {
11554                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11555                   clonedNodes[node] = clone;
11556                 }
11557               else
11558                 clone = clonedNodes[node];
11559
11560               if (isMedium)
11561                 ln3.push_back(clone);
11562               else
11563                 ln1.push_back(clone);
11564
11565               const SMDS_MeshNode* inter = 0;
11566               if (isQuad && (!isMedium))
11567                 {
11568                   if (!intermediateNodes.count(node))
11569                     {
11570                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11571                       intermediateNodes[node] = inter;
11572                     }
11573                   else
11574                     inter = intermediateNodes[node];
11575                   ln4.push_back(inter);
11576                 }
11577             }
11578
11579           // --- extrude the face
11580
11581           vector<const SMDS_MeshNode*> ln;
11582           SMDS_MeshVolume* vol = 0;
11583           vtkIdType aType = aFace->GetVtkType();
11584           switch (aType)
11585           {
11586             case VTK_TRIANGLE:
11587               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11588               // MESSAGE("vol prism " << vol->GetID());
11589               ln.push_back(ln1[0]);
11590               ln.push_back(ln1[1]);
11591               ln.push_back(ln1[2]);
11592               break;
11593             case VTK_QUAD:
11594               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11595               // MESSAGE("vol hexa " << vol->GetID());
11596               ln.push_back(ln1[0]);
11597               ln.push_back(ln1[1]);
11598               ln.push_back(ln1[2]);
11599               ln.push_back(ln1[3]);
11600               break;
11601             case VTK_QUADRATIC_TRIANGLE:
11602               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11603                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11604               // MESSAGE("vol quad prism " << vol->GetID());
11605               ln.push_back(ln1[0]);
11606               ln.push_back(ln1[1]);
11607               ln.push_back(ln1[2]);
11608               ln.push_back(ln3[0]);
11609               ln.push_back(ln3[1]);
11610               ln.push_back(ln3[2]);
11611               break;
11612             case VTK_QUADRATIC_QUAD:
11613 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11614 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11615 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11616               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11617                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11618                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11619               // MESSAGE("vol quad hexa " << vol->GetID());
11620               ln.push_back(ln1[0]);
11621               ln.push_back(ln1[1]);
11622               ln.push_back(ln1[2]);
11623               ln.push_back(ln1[3]);
11624               ln.push_back(ln3[0]);
11625               ln.push_back(ln3[1]);
11626               ln.push_back(ln3[2]);
11627               ln.push_back(ln3[3]);
11628               break;
11629             case VTK_POLYGON:
11630               break;
11631             default:
11632               break;
11633           }
11634
11635           if (vol)
11636             {
11637               stringstream grpname;
11638               grpname << "jf_";
11639               grpname << idom;
11640               int idg;
11641               string namegrp = grpname.str();
11642               if (!mapOfJunctionGroups.count(namegrp))
11643                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11644               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11645               if (sgrp)
11646                 sgrp->Add(vol->GetID());
11647             }
11648
11649           // --- modify the face
11650
11651           aFace->ChangeNodes(&ln[0], ln.size());
11652         }
11653     }
11654   return true;
11655 }
11656
11657 //================================================================================
11658 /*!
11659  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11660  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11661  * \return TRUE if operation has been completed successfully, FALSE otherwise
11662  */
11663 //================================================================================
11664
11665 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11666 {
11667   // iterates on volume elements and detect all free faces on them
11668   SMESHDS_Mesh* aMesh = GetMeshDS();
11669   if (!aMesh)
11670     return false;
11671   //bool res = false;
11672   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11673   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11674   while(vIt->more())
11675   {
11676     const SMDS_MeshVolume* volume = vIt->next();
11677     SMDS_VolumeTool vTool( volume );
11678     vTool.SetExternalNormal();
11679     const bool isPoly = volume->IsPoly();
11680     const bool isQuad = volume->IsQuadratic();
11681     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11682     {
11683       if (!vTool.IsFreeFace(iface))
11684         continue;
11685       nbFree++;
11686       vector<const SMDS_MeshNode *> nodes;
11687       int nbFaceNodes = vTool.NbFaceNodes(iface);
11688       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11689       int inode = 0;
11690       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11691         nodes.push_back(faceNodes[inode]);
11692       if (isQuad)
11693         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11694           nodes.push_back(faceNodes[inode]);
11695
11696       // add new face based on volume nodes
11697       if (aMesh->FindFace( nodes ) ) {
11698         nbExisted++;
11699         continue; // face already exsist
11700       }
11701       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11702       nbCreated++;
11703     }
11704   }
11705   return ( nbFree==(nbExisted+nbCreated) );
11706 }
11707
11708 namespace
11709 {
11710   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11711   {
11712     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11713       return n;
11714     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11715   }
11716 }
11717 //================================================================================
11718 /*!
11719  * \brief Creates missing boundary elements
11720  *  \param elements - elements whose boundary is to be checked
11721  *  \param dimension - defines type of boundary elements to create
11722  *  \param group - a group to store created boundary elements in
11723  *  \param targetMesh - a mesh to store created boundary elements in
11724  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11725  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
11726  *                                boundary elements will be copied into the targetMesh
11727  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11728  *                                boundary elements will be added into the new group
11729  *  \param aroundElements - if true, elements will be created on boundary of given
11730  *                          elements else, on boundary of the whole mesh.
11731  * \return nb of added boundary elements
11732  */
11733 //================================================================================
11734
11735 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11736                                        Bnd_Dimension           dimension,
11737                                        SMESH_Group*            group/*=0*/,
11738                                        SMESH_Mesh*             targetMesh/*=0*/,
11739                                        bool                    toCopyElements/*=false*/,
11740                                        bool                    toCopyExistingBoundary/*=false*/,
11741                                        bool                    toAddExistingBondary/*= false*/,
11742                                        bool                    aroundElements/*= false*/)
11743 {
11744   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11745   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11746   // hope that all elements are of the same type, do not check them all
11747   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11748     throw SALOME_Exception(LOCALIZED("wrong element type"));
11749
11750   if ( !targetMesh )
11751     toCopyElements = toCopyExistingBoundary = false;
11752
11753   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11754   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11755   int nbAddedBnd = 0;
11756
11757   // editor adding present bnd elements and optionally holding elements to add to the group
11758   SMESH_MeshEditor* presentEditor;
11759   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11760   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11761
11762   SMDS_VolumeTool vTool;
11763   TIDSortedElemSet avoidSet;
11764   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11765   int inode;
11766
11767   typedef vector<const SMDS_MeshNode*> TConnectivity;
11768
11769   SMDS_ElemIteratorPtr eIt;
11770   if (elements.empty())
11771     eIt = aMesh->elementsIterator(elemType);
11772   else
11773     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11774
11775   while (eIt->more())
11776   {
11777     const SMDS_MeshElement* elem = eIt->next();
11778     const int iQuad = elem->IsQuadratic();
11779
11780     // ------------------------------------------------------------------------------------
11781     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11782     // ------------------------------------------------------------------------------------
11783     vector<const SMDS_MeshElement*> presentBndElems;
11784     vector<TConnectivity>           missingBndElems;
11785     TConnectivity nodes;
11786     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11787     {
11788       vTool.SetExternalNormal();
11789       const SMDS_MeshElement* otherVol = 0;
11790       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11791       {
11792         if ( !vTool.IsFreeFace(iface, &otherVol) &&
11793              ( !aroundElements || elements.count( otherVol )))
11794           continue;
11795         const int nbFaceNodes = vTool.NbFaceNodes(iface);
11796         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11797         if ( missType == SMDSAbs_Edge ) // boundary edges
11798         {
11799           nodes.resize( 2+iQuad );
11800           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11801           {
11802             for ( int j = 0; j < nodes.size(); ++j )
11803               nodes[j] =nn[i+j];
11804             if ( const SMDS_MeshElement* edge =
11805                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11806               presentBndElems.push_back( edge );
11807             else
11808               missingBndElems.push_back( nodes );
11809           }
11810         }
11811         else // boundary face
11812         {
11813           nodes.clear();
11814           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11815             nodes.push_back( nn[inode] );
11816           if (iQuad)
11817             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11818               nodes.push_back( nn[inode] );
11819
11820           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11821             presentBndElems.push_back( f );
11822           else
11823             missingBndElems.push_back( nodes );
11824
11825           if ( targetMesh != myMesh )
11826           {
11827             // add 1D elements on face boundary to be added to a new mesh
11828             const SMDS_MeshElement* edge;
11829             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11830             {
11831               if ( iQuad )
11832                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11833               else
11834                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11835               if ( edge && avoidSet.insert( edge ).second )
11836                 presentBndElems.push_back( edge );
11837             }
11838           }
11839         }
11840       }
11841     }
11842     else                     // elem is a face ------------------------------------------
11843     {
11844       avoidSet.clear(), avoidSet.insert( elem );
11845       int nbNodes = elem->NbCornerNodes();
11846       nodes.resize( 2 /*+ iQuad*/);
11847       for ( int i = 0; i < nbNodes; i++ )
11848       {
11849         nodes[0] = elem->GetNode(i);
11850         nodes[1] = elem->GetNode((i+1)%nbNodes);
11851         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11852           continue; // not free link
11853
11854         //if ( iQuad )
11855         //nodes[2] = elem->GetNode( i + nbNodes );
11856         if ( const SMDS_MeshElement* edge =
11857              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11858           presentBndElems.push_back( edge );
11859         else
11860           missingBndElems.push_back( nodes );
11861       }
11862     }
11863
11864     // ---------------------------------
11865     // 2. Add missing boundary elements
11866     // ---------------------------------
11867     if ( targetMesh != myMesh )
11868       // instead of making a map of nodes in this mesh and targetMesh,
11869       // we create nodes with same IDs.
11870       for ( int i = 0; i < missingBndElems.size(); ++i )
11871       {
11872         TConnectivity& srcNodes = missingBndElems[i];
11873         TConnectivity  nodes( srcNodes.size() );
11874         for ( inode = 0; inode < nodes.size(); ++inode )
11875           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11876         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11877                                                                    missType,
11878                                                                    /*noMedium=*/true))
11879           continue;
11880         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11881         ++nbAddedBnd;
11882       }
11883     else
11884       for ( int i = 0; i < missingBndElems.size(); ++i )
11885       {
11886         TConnectivity& nodes = missingBndElems[i];
11887         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11888                                                                    missType,
11889                                                                    /*noMedium=*/true))
11890           continue;
11891         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11892         ++nbAddedBnd;
11893       }
11894
11895     // ----------------------------------
11896     // 3. Copy present boundary elements
11897     // ----------------------------------
11898     if ( toCopyExistingBoundary )
11899       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11900       {
11901         const SMDS_MeshElement* e = presentBndElems[i];
11902         TConnectivity nodes( e->NbNodes() );
11903         for ( inode = 0; inode < nodes.size(); ++inode )
11904           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11905         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11906       }
11907     else // store present elements to add them to a group
11908       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11909       {
11910         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11911       }
11912       
11913   } // loop on given elements
11914
11915   // ---------------------------------------------
11916   // 4. Fill group with boundary elements
11917   // ---------------------------------------------
11918   if ( group )
11919   {
11920     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11921       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11922         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11923   }
11924   tgtEditor.myLastCreatedElems.Clear();
11925   tgtEditor2.myLastCreatedElems.Clear();
11926
11927   // -----------------------
11928   // 5. Copy given elements
11929   // -----------------------
11930   if ( toCopyElements && targetMesh != myMesh )
11931   {
11932     if (elements.empty())
11933       eIt = aMesh->elementsIterator(elemType);
11934     else
11935       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11936     while (eIt->more())
11937     {
11938       const SMDS_MeshElement* elem = eIt->next();
11939       TConnectivity nodes( elem->NbNodes() );
11940       for ( inode = 0; inode < nodes.size(); ++inode )
11941         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11942       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11943
11944       tgtEditor.myLastCreatedElems.Clear();
11945     }
11946   }
11947   return nbAddedBnd;
11948 }