Salome HOME
0021542: EDF 1699 SMESH: Reorient a group of faces
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27
28 #include "SMESH_MeshEditor.hxx"
29
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_FacePosition.hxx"
34 #include "SMDS_SpacePosition.hxx"
35 #include "SMDS_MeshGroup.hxx"
36 #include "SMDS_LinearEdge.hxx"
37 #include "SMDS_Downward.hxx"
38 #include "SMDS_SetIterator.hxx"
39
40 #include "SMESHDS_Group.hxx"
41 #include "SMESHDS_Mesh.hxx"
42
43 #include "SMESH_Algo.hxx"
44 #include "SMESH_ControlsDef.hxx"
45 #include "SMESH_Group.hxx"
46 #include "SMESH_MesherHelper.hxx"
47 #include "SMESH_OctreeNode.hxx"
48 #include "SMESH_subMesh.hxx"
49
50 #include <Basics_OCCTVersion.hxx>
51
52 #include "utilities.h"
53
54 #include <BRepAdaptor_Surface.hxx>
55 #include <BRepBuilderAPI_MakeEdge.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
58 #include <ElCLib.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
74 #include <TopExp.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
79 #include <TopoDS.hxx>
80 #include <TopoDS_Face.hxx>
81 #include <gp.hxx>
82 #include <gp_Ax1.hxx>
83 #include <gp_Dir.hxx>
84 #include <gp_Lin.hxx>
85 #include <gp_Pln.hxx>
86 #include <gp_Trsf.hxx>
87 #include <gp_Vec.hxx>
88 #include <gp_XY.hxx>
89 #include <gp_XYZ.hxx>
90
91 #include <cmath>
92
93 #include <map>
94 #include <set>
95 #include <numeric>
96 #include <limits>
97 #include <algorithm>
98 #include <sstream>
99
100 #include <Standard_Failure.hxx>
101 #include <Standard_ErrorHandler.hxx>
102
103 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
104
105 using namespace std;
106 using namespace SMESH::Controls;
107
108 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
109 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
110
111 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
112
113 //=======================================================================
114 //function : SMESH_MeshEditor
115 //purpose  :
116 //=======================================================================
117
118 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
119   :myMesh( theMesh ) // theMesh may be NULL
120 {
121 }
122
123 //=======================================================================
124 /*!
125  * \brief Add element
126  */
127 //=======================================================================
128
129 SMDS_MeshElement*
130 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
131                              const SMDSAbs_ElementType            type,
132                              const bool                           isPoly,
133                              const int                            ID)
134 {
135   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
136   SMDS_MeshElement* e = 0;
137   int nbnode = node.size();
138   SMESHDS_Mesh* mesh = GetMeshDS();
139   switch ( type ) {
140   case SMDSAbs_Face:
141     if ( !isPoly ) {
142       if      (nbnode == 3) {
143         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
144         else           e = mesh->AddFace      (node[0], node[1], node[2] );
145       }
146       else if (nbnode == 4) {
147         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
148         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
149       }
150       else if (nbnode == 6) {
151         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
152                                                node[4], node[5], ID);
153         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
154                                                node[4], node[5] );
155       }
156       else if (nbnode == 8) {
157         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
158                                                node[4], node[5], node[6], node[7], ID);
159         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
160                                                node[4], node[5], node[6], node[7] );
161       }
162       else if (nbnode == 9) {
163         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
164                                                node[4], node[5], node[6], node[7], node[8], ID);
165         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
166                                                node[4], node[5], node[6], node[7], node[8] );
167       }
168     } else {
169       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
170       else           e = mesh->AddPolygonalFace      (node    );
171     }
172     break;
173
174   case SMDSAbs_Volume:
175     if ( !isPoly ) {
176       if      (nbnode == 4) {
177         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
178         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
179       }
180       else if (nbnode == 5) {
181         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
182                                                  node[4], ID);
183         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
184                                                  node[4] );
185       }
186       else if (nbnode == 6) {
187         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
188                                                  node[4], node[5], ID);
189         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
190                                                  node[4], node[5] );
191       }
192       else if (nbnode == 8) {
193         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
194                                                  node[4], node[5], node[6], node[7], ID);
195         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
196                                                  node[4], node[5], node[6], node[7] );
197       }
198       else if (nbnode == 10) {
199         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
200                                                  node[4], node[5], node[6], node[7],
201                                                  node[8], node[9], ID);
202         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
203                                                  node[4], node[5], node[6], node[7],
204                                                  node[8], node[9] );
205       }
206       else if (nbnode == 12) {
207         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
208                                                  node[4], node[5], node[6], node[7],
209                                                  node[8], node[9], node[10], node[11], ID);
210         else           e = mesh->AddVolume      (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       }
214       else if (nbnode == 13) {
215         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
216                                                  node[4], node[5], node[6], node[7],
217                                                  node[8], node[9], node[10],node[11],
218                                                  node[12],ID);
219         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
220                                                  node[4], node[5], node[6], node[7],
221                                                  node[8], node[9], node[10],node[11],
222                                                  node[12] );
223       }
224       else if (nbnode == 15) {
225         if ( ID >= 1 ) e = mesh->AddVolumeWithID(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],ID);
229         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
230                                                  node[4], node[5], node[6], node[7],
231                                                  node[8], node[9], node[10],node[11],
232                                                  node[12],node[13],node[14] );
233       }
234       else if (nbnode == 20) {
235         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
236                                                  node[4], node[5], node[6], node[7],
237                                                  node[8], node[9], node[10],node[11],
238                                                  node[12],node[13],node[14],node[15],
239                                                  node[16],node[17],node[18],node[19],ID);
240         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
241                                                  node[4], node[5], node[6], node[7],
242                                                  node[8], node[9], node[10],node[11],
243                                                  node[12],node[13],node[14],node[15],
244                                                  node[16],node[17],node[18],node[19] );
245       }
246       else if (nbnode == 27) {
247         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
248                                                  node[4], node[5], node[6], node[7],
249                                                  node[8], node[9], node[10],node[11],
250                                                  node[12],node[13],node[14],node[15],
251                                                  node[16],node[17],node[18],node[19],
252                                                  node[20],node[21],node[22],node[23],
253                                                  node[24],node[25],node[26], ID);
254         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
255                                                  node[4], node[5], node[6], node[7],
256                                                  node[8], node[9], node[10],node[11],
257                                                  node[12],node[13],node[14],node[15],
258                                                  node[16],node[17],node[18],node[19],
259                                                  node[20],node[21],node[22],node[23],
260                                                  node[24],node[25],node[26] );
261       }
262     }
263     break;
264
265   case SMDSAbs_Edge:
266     if ( nbnode == 2 ) {
267       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
268       else           e = mesh->AddEdge      (node[0], node[1] );
269     }
270     else if ( nbnode == 3 ) {
271       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
272       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
273     }
274     break;
275
276   case SMDSAbs_0DElement:
277     if ( nbnode == 1 ) {
278       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
279       else           e = mesh->Add0DElement      (node[0] );
280     }
281     break;
282
283   case SMDSAbs_Node:
284     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
285     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
286     break;
287
288   default:;
289   }
290   if ( e ) myLastCreatedElems.Append( e );
291   return e;
292 }
293
294 //=======================================================================
295 /*!
296  * \brief Add element
297  */
298 //=======================================================================
299
300 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
301                                                const SMDSAbs_ElementType type,
302                                                const bool                isPoly,
303                                                const int                 ID)
304 {
305   vector<const SMDS_MeshNode*> nodes;
306   nodes.reserve( nodeIDs.size() );
307   vector<int>::const_iterator id = nodeIDs.begin();
308   while ( id != nodeIDs.end() ) {
309     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
310       nodes.push_back( node );
311     else
312       return 0;
313   }
314   return AddElement( nodes, type, isPoly, ID );
315 }
316
317 //=======================================================================
318 //function : Remove
319 //purpose  : Remove a node or an element.
320 //           Modify a compute state of sub-meshes which become empty
321 //=======================================================================
322
323 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
324                               const bool         isNodes )
325 {
326   myLastCreatedElems.Clear();
327   myLastCreatedNodes.Clear();
328
329   SMESHDS_Mesh* aMesh = GetMeshDS();
330   set< SMESH_subMesh *> smmap;
331
332   int removed = 0;
333   list<int>::const_iterator it = theIDs.begin();
334   for ( ; it != theIDs.end(); it++ ) {
335     const SMDS_MeshElement * elem;
336     if ( isNodes )
337       elem = aMesh->FindNode( *it );
338     else
339       elem = aMesh->FindElement( *it );
340     if ( !elem )
341       continue;
342
343     // Notify VERTEX sub-meshes about modification
344     if ( isNodes ) {
345       const SMDS_MeshNode* node = cast2Node( elem );
346       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
347         if ( int aShapeID = node->getshapeId() )
348           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
349             smmap.insert( sm );
350     }
351     // Find sub-meshes to notify about modification
352     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
353     //     while ( nodeIt->more() ) {
354     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
355     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
356     //       if ( aPosition.get() ) {
357     //         if ( int aShapeID = aPosition->GetShapeId() ) {
358     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
359     //             smmap.insert( sm );
360     //         }
361     //       }
362     //     }
363
364     // Do remove
365     if ( isNodes )
366       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
367     else
368       aMesh->RemoveElement( elem );
369     removed++;
370   }
371
372   // Notify sub-meshes about modification
373   if ( !smmap.empty() ) {
374     set< SMESH_subMesh *>::iterator smIt;
375     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
376       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
377   }
378
379   //   // Check if the whole mesh becomes empty
380   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
381   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
382
383   return removed;
384 }
385
386 //=======================================================================
387 //function : FindShape
388 //purpose  : Return an index of the shape theElem is on
389 //           or zero if a shape not found
390 //=======================================================================
391
392 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
393 {
394   myLastCreatedElems.Clear();
395   myLastCreatedNodes.Clear();
396
397   SMESHDS_Mesh * aMesh = GetMeshDS();
398   if ( aMesh->ShapeToMesh().IsNull() )
399     return 0;
400
401   int aShapeID = theElem->getshapeId();
402   if ( aShapeID < 1 )
403     return 0;
404
405   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
406     if ( sm->Contains( theElem ))
407       return aShapeID;
408
409   if ( theElem->GetType() == SMDSAbs_Node ) {
410     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
411   }
412   else {
413     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
414   }
415
416   TopoDS_Shape aShape; // the shape a node of theElem is on
417   if ( theElem->GetType() != SMDSAbs_Node )
418   {
419     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
420     while ( nodeIt->more() ) {
421       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
422       if ((aShapeID = node->getshapeId()) > 0) {
423         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
424           if ( sm->Contains( theElem ))
425             return aShapeID;
426           if ( aShape.IsNull() )
427             aShape = aMesh->IndexToShape( aShapeID );
428         }
429       }
430     }
431   }
432
433   // None of nodes is on a proper shape,
434   // find the shape among ancestors of aShape on which a node is
435   if ( !aShape.IsNull() ) {
436     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
437     for ( ; ancIt.More(); ancIt.Next() ) {
438       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
439       if ( sm && sm->Contains( theElem ))
440         return aMesh->ShapeToIndex( ancIt.Value() );
441     }
442   }
443   else
444   {
445     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
446     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
447     for ( ; id_sm != id2sm.end(); ++id_sm )
448       if ( id_sm->second->Contains( theElem ))
449         return id_sm->first;
450   }
451
452   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
453   return 0;
454 }
455
456 //=======================================================================
457 //function : IsMedium
458 //purpose  :
459 //=======================================================================
460
461 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
462                                 const SMDSAbs_ElementType typeToCheck)
463 {
464   bool isMedium = false;
465   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
466   while (it->more() && !isMedium ) {
467     const SMDS_MeshElement* elem = it->next();
468     isMedium = elem->IsMediumNode(node);
469   }
470   return isMedium;
471 }
472
473 //=======================================================================
474 //function : ShiftNodesQuadTria
475 //purpose  : auxilary
476 //           Shift nodes in the array corresponded to quadratic triangle
477 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
478 //=======================================================================
479 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
480 {
481   const SMDS_MeshNode* nd1 = aNodes[0];
482   aNodes[0] = aNodes[1];
483   aNodes[1] = aNodes[2];
484   aNodes[2] = nd1;
485   const SMDS_MeshNode* nd2 = aNodes[3];
486   aNodes[3] = aNodes[4];
487   aNodes[4] = aNodes[5];
488   aNodes[5] = nd2;
489 }
490
491 //=======================================================================
492 //function : edgeConnectivity
493 //purpose  : auxilary 
494 //           return number of the edges connected with the theNode.
495 //           if theEdges has connections with the other type of the
496 //           elements, return -1 
497 //=======================================================================
498 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
499 {
500   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
501   int nb=0;
502   while(elemIt->more()) {
503     elemIt->next();
504     nb++;
505   }
506   return nb;
507 }
508
509
510 //=======================================================================
511 //function : GetNodesFromTwoTria
512 //purpose  : auxilary
513 //           Shift nodes in the array corresponded to quadratic triangle
514 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
515 //=======================================================================
516 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
517                                 const SMDS_MeshElement * theTria2,
518                                 const SMDS_MeshNode* N1[],
519                                 const SMDS_MeshNode* N2[])
520 {
521   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
522   int i=0;
523   while(i<6) {
524     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
525     i++;
526   }
527   if(it->more()) return false;
528   it = theTria2->nodesIterator();
529   i=0;
530   while(i<6) {
531     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
532     i++;
533   }
534   if(it->more()) return false;
535
536   int sames[3] = {-1,-1,-1};
537   int nbsames = 0;
538   int j;
539   for(i=0; i<3; i++) {
540     for(j=0; j<3; j++) {
541       if(N1[i]==N2[j]) {
542         sames[i] = j;
543         nbsames++;
544         break;
545       }
546     }
547   }
548   if(nbsames!=2) return false;
549   if(sames[0]>-1) {
550     ShiftNodesQuadTria(N1);
551     if(sames[1]>-1) {
552       ShiftNodesQuadTria(N1);
553     }
554   }
555   i = sames[0] + sames[1] + sames[2];
556   for(; i<2; i++) {
557     ShiftNodesQuadTria(N2);
558   }
559   // now we receive following N1 and N2 (using numeration as above image)
560   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
561   // i.e. first nodes from both arrays determ new diagonal
562   return true;
563 }
564
565 //=======================================================================
566 //function : InverseDiag
567 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
568 //           but having other common link.
569 //           Return False if args are improper
570 //=======================================================================
571
572 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
573                                     const SMDS_MeshElement * theTria2 )
574 {
575   MESSAGE("InverseDiag");
576   myLastCreatedElems.Clear();
577   myLastCreatedNodes.Clear();
578
579   if (!theTria1 || !theTria2)
580     return false;
581
582   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
583   if (!F1) return false;
584   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
585   if (!F2) return false;
586   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
587       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
588
589     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
590     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
591     //    |/ |                                         | \|
592     //  B +--+ 2                                     B +--+ 2
593
594     // put nodes in array and find out indices of the same ones
595     const SMDS_MeshNode* aNodes [6];
596     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
597     int i = 0;
598     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
599     while ( it->more() ) {
600       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
601
602       if ( i > 2 ) // theTria2
603         // find same node of theTria1
604         for ( int j = 0; j < 3; j++ )
605           if ( aNodes[ i ] == aNodes[ j ]) {
606             sameInd[ j ] = i;
607             sameInd[ i ] = j;
608             break;
609           }
610       // next
611       i++;
612       if ( i == 3 ) {
613         if ( it->more() )
614           return false; // theTria1 is not a triangle
615         it = theTria2->nodesIterator();
616       }
617       if ( i == 6 && it->more() )
618         return false; // theTria2 is not a triangle
619     }
620
621     // find indices of 1,2 and of A,B in theTria1
622     int iA = 0, iB = 0, i1 = 0, i2 = 0;
623     for ( i = 0; i < 6; i++ ) {
624       if ( sameInd [ i ] == 0 ) {
625         if ( i < 3 ) i1 = i;
626         else         i2 = i;
627       }
628       else if (i < 3) {
629         if ( iA ) iB = i;
630         else      iA = i;
631       }
632     }
633     // nodes 1 and 2 should not be the same
634     if ( aNodes[ i1 ] == aNodes[ i2 ] )
635       return false;
636
637     // theTria1: A->2
638     aNodes[ iA ] = aNodes[ i2 ];
639     // theTria2: B->1
640     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
641
642     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
643     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
644
645     return true;
646
647   } // end if(F1 && F2)
648
649   // check case of quadratic faces
650   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
651     return false;
652   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
653     return false;
654
655   //       5
656   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
657   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
658   //    |   / |
659   //  7 +  +  + 6
660   //    | /9  |
661   //    |/    |
662   //  4 +--+--+ 3
663   //       8
664
665   const SMDS_MeshNode* N1 [6];
666   const SMDS_MeshNode* N2 [6];
667   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
668     return false;
669   // now we receive following N1 and N2 (using numeration as above image)
670   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
671   // i.e. first nodes from both arrays determ new diagonal
672
673   const SMDS_MeshNode* N1new [6];
674   const SMDS_MeshNode* N2new [6];
675   N1new[0] = N1[0];
676   N1new[1] = N2[0];
677   N1new[2] = N2[1];
678   N1new[3] = N1[4];
679   N1new[4] = N2[3];
680   N1new[5] = N1[5];
681   N2new[0] = N1[0];
682   N2new[1] = N1[1];
683   N2new[2] = N2[0];
684   N2new[3] = N1[3];
685   N2new[4] = N2[5];
686   N2new[5] = N1[4];
687   // replaces nodes in faces
688   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
689   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
690
691   return true;
692 }
693
694 //=======================================================================
695 //function : findTriangles
696 //purpose  : find triangles sharing theNode1-theNode2 link
697 //=======================================================================
698
699 static bool findTriangles(const SMDS_MeshNode *    theNode1,
700                           const SMDS_MeshNode *    theNode2,
701                           const SMDS_MeshElement*& theTria1,
702                           const SMDS_MeshElement*& theTria2)
703 {
704   if ( !theNode1 || !theNode2 ) return false;
705
706   theTria1 = theTria2 = 0;
707
708   set< const SMDS_MeshElement* > emap;
709   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
710   while (it->more()) {
711     const SMDS_MeshElement* elem = it->next();
712     if ( elem->NbNodes() == 3 )
713       emap.insert( elem );
714   }
715   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
716   while (it->more()) {
717     const SMDS_MeshElement* elem = it->next();
718     if ( emap.find( elem ) != emap.end() ) {
719       if ( theTria1 ) {
720         // theTria1 must be element with minimum ID
721         if( theTria1->GetID() < elem->GetID() ) {
722           theTria2 = elem;
723         }
724         else {
725           theTria2 = theTria1;
726           theTria1 = elem;
727         }
728         break;
729       }
730       else {
731         theTria1 = elem;
732       }
733     }
734   }
735   return ( theTria1 && theTria2 );
736 }
737
738 //=======================================================================
739 //function : InverseDiag
740 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
741 //           with ones built on the same 4 nodes but having other common link.
742 //           Return false if proper faces not found
743 //=======================================================================
744
745 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
746                                     const SMDS_MeshNode * theNode2)
747 {
748   myLastCreatedElems.Clear();
749   myLastCreatedNodes.Clear();
750
751   MESSAGE( "::InverseDiag()" );
752
753   const SMDS_MeshElement *tr1, *tr2;
754   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
755     return false;
756
757   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
758   if (!F1) return false;
759   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
760   if (!F2) return false;
761   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
762       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
763
764     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
765     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
766     //    |/ |                                    | \|
767     //  B +--+ 2                                B +--+ 2
768
769     // put nodes in array
770     // and find indices of 1,2 and of A in tr1 and of B in tr2
771     int i, iA1 = 0, i1 = 0;
772     const SMDS_MeshNode* aNodes1 [3];
773     SMDS_ElemIteratorPtr it;
774     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
775       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
776       if ( aNodes1[ i ] == theNode1 )
777         iA1 = i; // node A in tr1
778       else if ( aNodes1[ i ] != theNode2 )
779         i1 = i;  // node 1
780     }
781     int iB2 = 0, i2 = 0;
782     const SMDS_MeshNode* aNodes2 [3];
783     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
784       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
785       if ( aNodes2[ i ] == theNode2 )
786         iB2 = i; // node B in tr2
787       else if ( aNodes2[ i ] != theNode1 )
788         i2 = i;  // node 2
789     }
790
791     // nodes 1 and 2 should not be the same
792     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
793       return false;
794
795     // tr1: A->2
796     aNodes1[ iA1 ] = aNodes2[ i2 ];
797     // tr2: B->1
798     aNodes2[ iB2 ] = aNodes1[ i1 ];
799
800     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
801     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
802
803     return true;
804   }
805
806   // check case of quadratic faces
807   return InverseDiag(tr1,tr2);
808 }
809
810 //=======================================================================
811 //function : getQuadrangleNodes
812 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
813 //           fusion of triangles tr1 and tr2 having shared link on
814 //           theNode1 and theNode2
815 //=======================================================================
816
817 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
818                         const SMDS_MeshNode *    theNode1,
819                         const SMDS_MeshNode *    theNode2,
820                         const SMDS_MeshElement * tr1,
821                         const SMDS_MeshElement * tr2 )
822 {
823   if( tr1->NbNodes() != tr2->NbNodes() )
824     return false;
825   // find the 4-th node to insert into tr1
826   const SMDS_MeshNode* n4 = 0;
827   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
828   int i=0;
829   while ( !n4 && i<3 ) {
830     const SMDS_MeshNode * n = cast2Node( it->next() );
831     i++;
832     bool isDiag = ( n == theNode1 || n == theNode2 );
833     if ( !isDiag )
834       n4 = n;
835   }
836   // Make an array of nodes to be in a quadrangle
837   int iNode = 0, iFirstDiag = -1;
838   it = tr1->nodesIterator();
839   i=0;
840   while ( i<3 ) {
841     const SMDS_MeshNode * n = cast2Node( it->next() );
842     i++;
843     bool isDiag = ( n == theNode1 || n == theNode2 );
844     if ( isDiag ) {
845       if ( iFirstDiag < 0 )
846         iFirstDiag = iNode;
847       else if ( iNode - iFirstDiag == 1 )
848         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
849     }
850     else if ( n == n4 ) {
851       return false; // tr1 and tr2 should not have all the same nodes
852     }
853     theQuadNodes[ iNode++ ] = n;
854   }
855   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
856     theQuadNodes[ iNode ] = n4;
857
858   return true;
859 }
860
861 //=======================================================================
862 //function : DeleteDiag
863 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
864 //           with a quadrangle built on the same 4 nodes.
865 //           Return false if proper faces not found
866 //=======================================================================
867
868 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
869                                    const SMDS_MeshNode * theNode2)
870 {
871   myLastCreatedElems.Clear();
872   myLastCreatedNodes.Clear();
873
874   MESSAGE( "::DeleteDiag()" );
875
876   const SMDS_MeshElement *tr1, *tr2;
877   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
878     return false;
879
880   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
881   if (!F1) return false;
882   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
883   if (!F2) return false;
884   SMESHDS_Mesh * aMesh = GetMeshDS();
885
886   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
887       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
888
889     const SMDS_MeshNode* aNodes [ 4 ];
890     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
891       return false;
892
893     const SMDS_MeshElement* newElem = 0;
894     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
895     myLastCreatedElems.Append(newElem);
896     AddToSameGroups( newElem, tr1, aMesh );
897     int aShapeId = tr1->getshapeId();
898     if ( aShapeId )
899       {
900         aMesh->SetMeshElementOnShape( newElem, aShapeId );
901       }
902     aMesh->RemoveElement( tr1 );
903     aMesh->RemoveElement( tr2 );
904
905     return true;
906   }
907
908   // check case of quadratic faces
909   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
910     return false;
911   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
912     return false;
913
914   //       5
915   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
916   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
917   //    |   / |
918   //  7 +  +  + 6
919   //    | /9  |
920   //    |/    |
921   //  4 +--+--+ 3
922   //       8
923
924   const SMDS_MeshNode* N1 [6];
925   const SMDS_MeshNode* N2 [6];
926   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
927     return false;
928   // now we receive following N1 and N2 (using numeration as above image)
929   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
930   // i.e. first nodes from both arrays determ new diagonal
931
932   const SMDS_MeshNode* aNodes[8];
933   aNodes[0] = N1[0];
934   aNodes[1] = N1[1];
935   aNodes[2] = N2[0];
936   aNodes[3] = N2[1];
937   aNodes[4] = N1[3];
938   aNodes[5] = N2[5];
939   aNodes[6] = N2[3];
940   aNodes[7] = N1[5];
941
942   const SMDS_MeshElement* newElem = 0;
943   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
944                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
945   myLastCreatedElems.Append(newElem);
946   AddToSameGroups( newElem, tr1, aMesh );
947   int aShapeId = tr1->getshapeId();
948   if ( aShapeId )
949     {
950       aMesh->SetMeshElementOnShape( newElem, aShapeId );
951     }
952   aMesh->RemoveElement( tr1 );
953   aMesh->RemoveElement( tr2 );
954
955   // remove middle node (9)
956   GetMeshDS()->RemoveNode( N1[4] );
957
958   return true;
959 }
960
961 //=======================================================================
962 //function : Reorient
963 //purpose  : Reverse theElement orientation
964 //=======================================================================
965
966 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
967 {
968   MESSAGE("Reorient");
969   myLastCreatedElems.Clear();
970   myLastCreatedNodes.Clear();
971
972   if (!theElem)
973     return false;
974   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
975   if ( !it || !it->more() )
976     return false;
977
978   switch ( theElem->GetType() ) {
979
980   case SMDSAbs_Edge:
981   case SMDSAbs_Face: {
982     if(!theElem->IsQuadratic()) {
983       int i = theElem->NbNodes();
984       vector<const SMDS_MeshNode*> aNodes( i );
985       while ( it->more() )
986         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
987       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
988     }
989     else {
990       // quadratic elements
991       if(theElem->GetType()==SMDSAbs_Edge) {
992         vector<const SMDS_MeshNode*> aNodes(3);
993         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
994         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
995         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
996         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
997       }
998       else {
999         int nbn = theElem->NbNodes();
1000         vector<const SMDS_MeshNode*> aNodes(nbn);
1001         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
1002         int i=1;
1003         for(; i<nbn/2; i++) {
1004           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
1005         }
1006         for(i=0; i<nbn/2; i++) {
1007           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
1008         }
1009         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
1010       }
1011     }
1012   }
1013   case SMDSAbs_Volume: {
1014     if (theElem->IsPoly()) {
1015       // TODO reorient vtk polyhedron
1016       MESSAGE("reorient vtk polyhedron ?");
1017       const SMDS_VtkVolume* aPolyedre =
1018         dynamic_cast<const SMDS_VtkVolume*>( theElem );
1019       if (!aPolyedre) {
1020         MESSAGE("Warning: bad volumic element");
1021         return false;
1022       }
1023
1024       int nbFaces = aPolyedre->NbFaces();
1025       vector<const SMDS_MeshNode *> poly_nodes;
1026       vector<int> quantities (nbFaces);
1027
1028       // reverse each face of the polyedre
1029       for (int iface = 1; iface <= nbFaces; iface++) {
1030         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1031         quantities[iface - 1] = nbFaceNodes;
1032
1033         for (inode = nbFaceNodes; inode >= 1; inode--) {
1034           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1035           poly_nodes.push_back(curNode);
1036         }
1037       }
1038
1039       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1040
1041     }
1042     else {
1043       SMDS_VolumeTool vTool;
1044       if ( !vTool.Set( theElem ))
1045         return false;
1046       vTool.Inverse();
1047       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
1048       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
1049     }
1050   }
1051   default:;
1052   }
1053
1054   return false;
1055 }
1056
1057 //================================================================================
1058 /*!
1059  * \brief Reorient faces.
1060  * \param theFaces - the faces to reorient. If empty the whole mesh is meant
1061  * \param theDirection - desired direction of normal of \a theFace
1062  * \param theFace - one of \a theFaces that sould be orientated according to
1063  *        \a theDirection and whose orientation defines orientation of other faces
1064  * \return number of reoriented faces.
1065  */
1066 //================================================================================
1067
1068 int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
1069                                   const gp_Dir&            theDirection,
1070                                   const SMDS_MeshElement * theFace)
1071 {
1072   int nbReori = 0;
1073   if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori;
1074
1075   if ( theFaces.empty() )
1076   {
1077     SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true);
1078     while ( fIt->more() )
1079       theFaces.insert( theFaces.end(), fIt->next() );
1080   }
1081
1082   // orient theFace according to theDirection
1083   gp_XYZ normal;
1084   SMESH_Algo::FaceNormal( theFace, normal, /*normalized=*/false );
1085   if ( normal * theDirection.XYZ() < 0 )
1086     nbReori += Reorient( theFace );
1087
1088   // Orient other faces
1089
1090   set< const SMDS_MeshElement* > startFaces;
1091   TIDSortedElemSet avoidSet;
1092   set< SMESH_TLink > checkedLinks;
1093   pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
1094
1095   if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
1096     theFaces.erase( theFace );
1097   startFaces.insert( theFace );
1098
1099   set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
1100   while ( startFace != startFaces.end() )
1101   {
1102     theFace = *startFace;
1103     const int nbNodes = theFace->NbCornerNodes();
1104
1105     avoidSet.clear();
1106     avoidSet.insert(theFace);
1107
1108     NLink link( theFace->GetNode( 0 ), 0 );
1109     for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
1110     {
1111       link.second = theFace->GetNode(( i+1 ) % nbNodes );
1112       linkIt_isNew = checkedLinks.insert( link );
1113       if ( !linkIt_isNew.second )
1114       {
1115         // link has already been checked and won't be encountered more
1116         // if the group (theFaces) is manifold
1117         checkedLinks.erase( linkIt_isNew.first );
1118       }
1119       else
1120       {
1121         int nodeInd1, nodeInd2;
1122         const SMDS_MeshElement* otherFace = FindFaceInSet( link.first, link.second,
1123                                                            theFaces, avoidSet,
1124                                                            & nodeInd1, & nodeInd2);
1125         if ( otherFace && otherFace != theFace)
1126         {
1127           // link must be reversed in otherFace if orientation ot otherFace
1128           // is same as that of theFace
1129           if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
1130           {
1131             // cout << "Reorient " << otherFace->GetID() << " near theFace=" <<theFace->GetID()
1132             //      << " \tlink( " << link.first->GetID() << " " << link.second->GetID() << endl;
1133             nbReori += Reorient( otherFace );
1134           }
1135           startFaces.insert( otherFace );
1136           if ( theFaces.size() > 1 ) // leave 1 face to prevent finding not selected faces
1137             theFaces.erase( otherFace );
1138         }
1139       }
1140       std::swap( link.first, link.second );
1141     }
1142     startFaces.erase( startFace );
1143     startFace = startFaces.begin();
1144   }
1145   return nbReori;
1146 }
1147
1148 //=======================================================================
1149 //function : getBadRate
1150 //purpose  :
1151 //=======================================================================
1152
1153 static double getBadRate (const SMDS_MeshElement*               theElem,
1154                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1155 {
1156   SMESH::Controls::TSequenceOfXYZ P;
1157   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1158     return 1e100;
1159   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1160   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1161 }
1162
1163 //=======================================================================
1164 //function : QuadToTri
1165 //purpose  : Cut quadrangles into triangles.
1166 //           theCrit is used to select a diagonal to cut
1167 //=======================================================================
1168
1169 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1170                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1171 {
1172   myLastCreatedElems.Clear();
1173   myLastCreatedNodes.Clear();
1174
1175   MESSAGE( "::QuadToTri()" );
1176
1177   if ( !theCrit.get() )
1178     return false;
1179
1180   SMESHDS_Mesh * aMesh = GetMeshDS();
1181
1182   Handle(Geom_Surface) surface;
1183   SMESH_MesherHelper   helper( *GetMesh() );
1184
1185   TIDSortedElemSet::iterator itElem;
1186   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1187     const SMDS_MeshElement* elem = *itElem;
1188     if ( !elem || elem->GetType() != SMDSAbs_Face )
1189       continue;
1190     if ( elem->NbCornerNodes() != 4 )
1191       continue;
1192
1193     // retrieve element nodes
1194     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1195
1196     // compare two sets of possible triangles
1197     double aBadRate1, aBadRate2; // to what extent a set is bad
1198     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1199     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1200     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1201
1202     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1203     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1204     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1205
1206     int aShapeId = FindShape( elem );
1207     const SMDS_MeshElement* newElem1 = 0;
1208     const SMDS_MeshElement* newElem2 = 0;
1209
1210     if( !elem->IsQuadratic() ) {
1211
1212       // split liner quadrangle
1213
1214       if ( aBadRate1 <= aBadRate2 ) {
1215         // tr1 + tr2 is better
1216         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1217         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1218       }
1219       else {
1220         // tr3 + tr4 is better
1221         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1222         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1223       }
1224     }
1225     else {
1226
1227       // split quadratic quadrangle
1228
1229       // get surface elem is on
1230       if ( aShapeId != helper.GetSubShapeID() ) {
1231         surface.Nullify();
1232         TopoDS_Shape shape;
1233         if ( aShapeId > 0 )
1234           shape = aMesh->IndexToShape( aShapeId );
1235         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1236           TopoDS_Face face = TopoDS::Face( shape );
1237           surface = BRep_Tool::Surface( face );
1238           if ( !surface.IsNull() )
1239             helper.SetSubShape( shape );
1240         }
1241       }
1242       // find middle point for (0,1,2,3)
1243       // and create a node in this point;
1244       const SMDS_MeshNode* newN = 0;
1245       if ( aNodes.size() == 9 )
1246       {
1247         // SMDSEntity_BiQuad_Quadrangle
1248         newN = aNodes.back();
1249       }
1250       else
1251       {
1252         gp_XYZ p( 0,0,0 );
1253         if ( surface.IsNull() )
1254         {
1255           for ( int i = 0; i < 4; i++ )
1256             p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1257           p /= 4;
1258         }
1259         else
1260         {
1261           const SMDS_MeshNode* inFaceNode = 0;
1262           if ( helper.GetNodeUVneedInFaceNode() )
1263             for ( size_t i = 0; i < aNodes.size() && !inFaceNode; ++i )
1264               if ( aNodes[ i ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1265                 inFaceNode = aNodes[ i ];
1266
1267           TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1268           gp_XY uv( 0,0 );
1269           for ( int i = 0; i < 4; i++ )
1270             uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1271           uv /= 4.;
1272           p = surface->Value( uv.X(), uv.Y() ).XYZ();
1273         }
1274         newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1275         myLastCreatedNodes.Append(newN);
1276       }
1277       // create a new element
1278       if ( aBadRate1 <= aBadRate2 ) {
1279         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1280                                   aNodes[6], aNodes[7], newN );
1281         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1282                                   newN,      aNodes[4], aNodes[5] );
1283       }
1284       else {
1285         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1286                                   aNodes[7], aNodes[4], newN );
1287         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1288                                   newN,      aNodes[5], aNodes[6] );
1289       }
1290     } // quadratic case
1291
1292     // care of a new element
1293
1294     myLastCreatedElems.Append(newElem1);
1295     myLastCreatedElems.Append(newElem2);
1296     AddToSameGroups( newElem1, elem, aMesh );
1297     AddToSameGroups( newElem2, elem, aMesh );
1298
1299     // put a new triangle on the same shape
1300     if ( aShapeId )
1301       {
1302         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1303         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1304       }
1305     aMesh->RemoveElement( elem );
1306   }
1307   return true;
1308 }
1309
1310 //=======================================================================
1311 //function : BestSplit
1312 //purpose  : Find better diagonal for cutting.
1313 //=======================================================================
1314
1315 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1316                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1317 {
1318   myLastCreatedElems.Clear();
1319   myLastCreatedNodes.Clear();
1320
1321   if (!theCrit.get())
1322     return -1;
1323
1324   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1325     return -1;
1326
1327   if( theQuad->NbNodes()==4 ||
1328       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1329
1330     // retrieve element nodes
1331     const SMDS_MeshNode* aNodes [4];
1332     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1333     int i = 0;
1334     //while (itN->more())
1335     while (i<4) {
1336       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1337     }
1338     // compare two sets of possible triangles
1339     double aBadRate1, aBadRate2; // to what extent a set is bad
1340     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1341     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1342     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1343
1344     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1345     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1346     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1347
1348     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1349       return 1; // diagonal 1-3
1350
1351     return 2; // diagonal 2-4
1352   }
1353   return -1;
1354 }
1355
1356 namespace
1357 {
1358   // Methods of splitting volumes into tetra
1359
1360   const int theHexTo5_1[5*4+1] =
1361     {
1362       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1363     };
1364   const int theHexTo5_2[5*4+1] =
1365     {
1366       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1367     };
1368   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1369
1370   const int theHexTo6_1[6*4+1] =
1371     {
1372       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
1373     };
1374   const int theHexTo6_2[6*4+1] =
1375     {
1376       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
1377     };
1378   const int theHexTo6_3[6*4+1] =
1379     {
1380       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
1381     };
1382   const int theHexTo6_4[6*4+1] =
1383     {
1384       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
1385     };
1386   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1387
1388   const int thePyraTo2_1[2*4+1] =
1389     {
1390       0, 1, 2, 4,    0, 2, 3, 4,   -1
1391     };
1392   const int thePyraTo2_2[2*4+1] =
1393     {
1394       1, 2, 3, 4,    1, 3, 0, 4,   -1
1395     };
1396   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1397
1398   const int thePentaTo3_1[3*4+1] =
1399     {
1400       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1401     };
1402   const int thePentaTo3_2[3*4+1] =
1403     {
1404       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1405     };
1406   const int thePentaTo3_3[3*4+1] =
1407     {
1408       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1409     };
1410   const int thePentaTo3_4[3*4+1] =
1411     {
1412       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1413     };
1414   const int thePentaTo3_5[3*4+1] =
1415     {
1416       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1417     };
1418   const int thePentaTo3_6[3*4+1] =
1419     {
1420       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1421     };
1422   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1423                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1424
1425   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1426   {
1427     int _n1, _n2, _n3;
1428     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1429     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1430     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1431   };
1432   struct TSplitMethod
1433   {
1434     int        _nbTetra;
1435     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1436     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1437     bool       _ownConn;      //!< to delete _connectivity in destructor
1438     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1439
1440     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1441       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1442     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1443     bool hasFacet( const TTriangleFacet& facet ) const
1444     {
1445       const int* tetConn = _connectivity;
1446       for ( ; tetConn[0] >= 0; tetConn += 4 )
1447         if (( facet.contains( tetConn[0] ) +
1448               facet.contains( tetConn[1] ) +
1449               facet.contains( tetConn[2] ) +
1450               facet.contains( tetConn[3] )) == 3 )
1451           return true;
1452       return false;
1453     }
1454   };
1455
1456   //=======================================================================
1457   /*!
1458    * \brief return TSplitMethod for the given element
1459    */
1460   //=======================================================================
1461
1462   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1463   {
1464     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1465
1466     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1467     // an edge and a face barycenter; tertaherdons are based on triangles and
1468     // a volume barycenter
1469     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1470
1471     // Find out how adjacent volumes are split
1472
1473     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1474     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1475     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1476     {
1477       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1478       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1479       if ( nbNodes < 4 ) continue;
1480
1481       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1482       const int* nInd = vol.GetFaceNodesIndices( iF );
1483       if ( nbNodes == 4 )
1484       {
1485         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1486         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1487         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1488         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1489       }
1490       else
1491       {
1492         int iCom = 0; // common node of triangle faces to split into
1493         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1494         {
1495           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1496                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1497                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1498           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1499                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1500                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1501           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1502           {
1503             triaSplits.push_back( t012 );
1504             triaSplits.push_back( t023 );
1505             break;
1506           }
1507         }
1508       }
1509       if ( !triaSplits.empty() )
1510         hasAdjacentSplits = true;
1511     }
1512
1513     // Among variants of split method select one compliant with adjacent volumes
1514
1515     TSplitMethod method;
1516     if ( !vol.Element()->IsPoly() && !is24TetMode )
1517     {
1518       int nbVariants = 2, nbTet = 0;
1519       const int** connVariants = 0;
1520       switch ( vol.Element()->GetEntityType() )
1521       {
1522       case SMDSEntity_Hexa:
1523       case SMDSEntity_Quad_Hexa:
1524       case SMDSEntity_TriQuad_Hexa:
1525         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1526           connVariants = theHexTo5, nbTet = 5;
1527         else
1528           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1529         break;
1530       case SMDSEntity_Pyramid:
1531       case SMDSEntity_Quad_Pyramid:
1532         connVariants = thePyraTo2;  nbTet = 2;
1533         break;
1534       case SMDSEntity_Penta:
1535       case SMDSEntity_Quad_Penta:
1536         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1537         break;
1538       default:
1539         nbVariants = 0;
1540       }
1541       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1542       {
1543         // check method compliancy with adjacent tetras,
1544         // all found splits must be among facets of tetras described by this method
1545         method = TSplitMethod( nbTet, connVariants[variant] );
1546         if ( hasAdjacentSplits && method._nbTetra > 0 )
1547         {
1548           bool facetCreated = true;
1549           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1550           {
1551             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1552             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1553               facetCreated = method.hasFacet( *facet );
1554           }
1555           if ( !facetCreated )
1556             method = TSplitMethod(0); // incompatible method
1557         }
1558       }
1559     }
1560     if ( method._nbTetra < 1 )
1561     {
1562       // No standard method is applicable, use a generic solution:
1563       // each facet of a volume is split into triangles and
1564       // each of triangles and a volume barycenter form a tetrahedron.
1565
1566       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1567
1568       int* connectivity = new int[ maxTetConnSize + 1 ];
1569       method._connectivity = connectivity;
1570       method._ownConn = true;
1571       method._baryNode = !isHex27; // to create central node or not
1572
1573       int connSize = 0;
1574       int baryCenInd = vol.NbNodes() - int( isHex27 );
1575       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1576       {
1577         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1578         const int*   nInd = vol.GetFaceNodesIndices( iF );
1579         // find common node of triangle facets of tetra to create
1580         int iCommon = 0; // index in linear numeration
1581         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1582         if ( !triaSplits.empty() )
1583         {
1584           // by found facets
1585           const TTriangleFacet* facet = &triaSplits.front();
1586           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1587             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1588                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1589               break;
1590         }
1591         else if ( nbNodes > 3 && !is24TetMode )
1592         {
1593           // find the best method of splitting into triangles by aspect ratio
1594           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1595           map< double, int > badness2iCommon;
1596           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1597           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1598           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1599           {
1600             double badness = 0;
1601             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1602             {
1603               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1604                                       nodes[ iQ*((iLast-1)%nbNodes)],
1605                                       nodes[ iQ*((iLast  )%nbNodes)]);
1606               badness += getBadRate( &tria, aspectRatio );
1607             }
1608             badness2iCommon.insert( make_pair( badness, iCommon ));
1609           }
1610           // use iCommon with lowest badness
1611           iCommon = badness2iCommon.begin()->second;
1612         }
1613         if ( iCommon >= nbNodes )
1614           iCommon = 0; // something wrong
1615
1616         // fill connectivity of tetrahedra based on a current face
1617         int nbTet = nbNodes - 2;
1618         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1619         {
1620           int faceBaryCenInd;
1621           if ( isHex27 )
1622           {
1623             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
1624             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
1625           }
1626           else
1627           {
1628             method._faceBaryNode[ iF ] = 0;
1629             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1630           }
1631           nbTet = nbNodes;
1632           for ( int i = 0; i < nbTet; ++i )
1633           {
1634             int i1 = i, i2 = (i+1) % nbNodes;
1635             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1636             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1637             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1638             connectivity[ connSize++ ] = faceBaryCenInd;
1639             connectivity[ connSize++ ] = baryCenInd;
1640           }
1641         }
1642         else
1643         {
1644           for ( int i = 0; i < nbTet; ++i )
1645           {
1646             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1647             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1648             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1649             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1650             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1651             connectivity[ connSize++ ] = baryCenInd;
1652           }
1653         }
1654         method._nbTetra += nbTet;
1655
1656       } // loop on volume faces
1657
1658       connectivity[ connSize++ ] = -1;
1659
1660     } // end of generic solution
1661
1662     return method;
1663   }
1664   //================================================================================
1665   /*!
1666    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1667    */
1668   //================================================================================
1669
1670   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1671   {
1672     // find the tetrahedron including the three nodes of facet
1673     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1674     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1675     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1676     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1677     while ( volIt1->more() )
1678     {
1679       const SMDS_MeshElement* v = volIt1->next();
1680       SMDSAbs_EntityType type = v->GetEntityType();
1681       if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
1682         continue;
1683       if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
1684         continue; // medium node not allowed
1685       const int ind2 = v->GetNodeIndex( n2 );
1686       if ( ind2 < 0 || 3 < ind2 )
1687         continue;
1688       const int ind3 = v->GetNodeIndex( n3 );
1689       if ( ind3 < 0 || 3 < ind3 )
1690         continue;
1691       return true;
1692     }
1693     return false;
1694   }
1695
1696   //=======================================================================
1697   /*!
1698    * \brief A key of a face of volume
1699    */
1700   //=======================================================================
1701
1702   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
1703   {
1704     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1705     {
1706       TIDSortedNodeSet sortedNodes;
1707       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1708       int nbNodes = vol.NbFaceNodes( iF );
1709       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1710       for ( int i = 0; i < nbNodes; i += iQ )
1711         sortedNodes.insert( fNodes[i] );
1712       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1713       first.first   = (*(n++))->GetID();
1714       first.second  = (*(n++))->GetID();
1715       second.first  = (*(n++))->GetID();
1716       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
1717     }
1718   };
1719 } // namespace
1720
1721 //=======================================================================
1722 //function : SplitVolumesIntoTetra
1723 //purpose  : Split volume elements into tetrahedra.
1724 //=======================================================================
1725
1726 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1727                                               const int                theMethodFlags)
1728 {
1729   // std-like iterator on coordinates of nodes of mesh element
1730   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1731   NXyzIterator xyzEnd;
1732
1733   SMDS_VolumeTool    volTool;
1734   SMESH_MesherHelper helper( *GetMesh());
1735
1736   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1737   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1738   
1739   SMESH_SequenceOfElemPtr newNodes, newElems;
1740
1741   // map face of volume to it's baricenrtic node
1742   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1743   double bc[3];
1744
1745   TIDSortedElemSet::const_iterator elem = theElems.begin();
1746   for ( ; elem != theElems.end(); ++elem )
1747   {
1748     if ( (*elem)->GetType() != SMDSAbs_Volume )
1749       continue;
1750     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1751     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
1752       continue;
1753
1754     if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
1755
1756     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1757     if ( splitMethod._nbTetra < 1 ) continue;
1758
1759     // find submesh to add new tetras to
1760     if ( !subMesh || !subMesh->Contains( *elem ))
1761     {
1762       int shapeID = FindShape( *elem );
1763       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1764       subMesh = GetMeshDS()->MeshElements( shapeID );
1765     }
1766     int iQ;
1767     if ( (*elem)->IsQuadratic() )
1768     {
1769       iQ = 2;
1770       // add quadratic links to the helper
1771       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1772       {
1773         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1774         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
1775         for ( int iN = 0; iN < nbN; iN += iQ )
1776           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
1777       }
1778       helper.SetIsQuadratic( true );
1779     }
1780     else
1781     {
1782       iQ = 1;
1783       helper.SetIsQuadratic( false );
1784     }
1785     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1786     helper.SetElementsOnShape( true );
1787     if ( splitMethod._baryNode )
1788     {
1789       // make a node at barycenter
1790       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1791       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1792       nodes.push_back( gcNode );
1793       newNodes.Append( gcNode );
1794     }
1795     if ( !splitMethod._faceBaryNode.empty() )
1796     {
1797       // make or find baricentric nodes of faces
1798       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1799       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1800       {
1801         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1802           volFace2BaryNode.insert
1803           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
1804         if ( !f_n->second )
1805         {
1806           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1807           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1808         }
1809         nodes.push_back( iF_n->second = f_n->second );
1810       }
1811     }
1812
1813     // make tetras
1814     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1815     const int* tetConn = splitMethod._connectivity;
1816     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1817       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1818                                                        nodes[ tetConn[1] ],
1819                                                        nodes[ tetConn[2] ],
1820                                                        nodes[ tetConn[3] ]));
1821
1822     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1823
1824     // Split faces on sides of the split volume
1825
1826     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1827     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1828     {
1829       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1830       if ( nbNodes < 4 ) continue;
1831
1832       // find an existing face
1833       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1834                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
1835       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
1836                                                                        /*noMedium=*/false))
1837       {
1838         // make triangles
1839         helper.SetElementsOnShape( false );
1840         vector< const SMDS_MeshElement* > triangles;
1841
1842         // find submesh to add new triangles in
1843         if ( !fSubMesh || !fSubMesh->Contains( face ))
1844         {
1845           int shapeID = FindShape( face );
1846           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1847         }
1848         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1849         if ( iF_n != splitMethod._faceBaryNode.end() )
1850         {
1851           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1852           {
1853             const SMDS_MeshNode* n1 = fNodes[iN];
1854             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
1855             const SMDS_MeshNode *n3 = iF_n->second;
1856             if ( !volTool.IsFaceExternal( iF ))
1857               swap( n2, n3 );
1858             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1859
1860             if ( fSubMesh && n3->getshapeId() < 1 )
1861               fSubMesh->AddNode( n3 );
1862           }
1863         }
1864         else
1865         {
1866           // among possible triangles create ones discribed by split method
1867           const int* nInd = volTool.GetFaceNodesIndices( iF );
1868           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1869           int iCom = 0; // common node of triangle faces to split into
1870           list< TTriangleFacet > facets;
1871           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1872           {
1873             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1874                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1875                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1876             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1877                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1878                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1879             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1880             {
1881               facets.push_back( t012 );
1882               facets.push_back( t023 );
1883               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1884                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1885                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1886                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1887               break;
1888             }
1889           }
1890           list< TTriangleFacet >::iterator facet = facets.begin();
1891           for ( ; facet != facets.end(); ++facet )
1892           {
1893             if ( !volTool.IsFaceExternal( iF ))
1894               swap( facet->_n2, facet->_n3 );
1895             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1896                                                  volNodes[ facet->_n2 ],
1897                                                  volNodes[ facet->_n3 ]));
1898           }
1899         }
1900         for ( int i = 0; i < triangles.size(); ++i )
1901         {
1902           if ( !triangles[i] ) continue;
1903           if ( fSubMesh )
1904             fSubMesh->AddElement( triangles[i]);
1905           newElems.Append( triangles[i] );
1906         }
1907         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1908         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1909       }
1910
1911     } // loop on volume faces to split them into triangles
1912
1913     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1914
1915     if ( geomType == SMDSEntity_TriQuad_Hexa )
1916     {
1917       // remove medium nodes that could become free
1918       for ( int i = 20; i < volTool.NbNodes(); ++i )
1919         if ( volNodes[i]->NbInverseElements() == 0 )
1920           GetMeshDS()->RemoveNode( volNodes[i] );
1921     }
1922   } // loop on volumes to split
1923
1924   myLastCreatedNodes = newNodes;
1925   myLastCreatedElems = newElems;
1926 }
1927
1928 //=======================================================================
1929 //function : AddToSameGroups
1930 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1931 //=======================================================================
1932
1933 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1934                                         const SMDS_MeshElement* elemInGroups,
1935                                         SMESHDS_Mesh *          aMesh)
1936 {
1937   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1938   if (!groups.empty()) {
1939     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1940     for ( ; grIt != groups.end(); grIt++ ) {
1941       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1942       if ( group && group->Contains( elemInGroups ))
1943         group->SMDSGroup().Add( elemToAdd );
1944     }
1945   }
1946 }
1947
1948
1949 //=======================================================================
1950 //function : RemoveElemFromGroups
1951 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1952 //=======================================================================
1953 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1954                                              SMESHDS_Mesh *          aMesh)
1955 {
1956   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1957   if (!groups.empty())
1958   {
1959     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1960     for (; GrIt != groups.end(); GrIt++)
1961     {
1962       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1963       if (!grp || grp->IsEmpty()) continue;
1964       grp->SMDSGroup().Remove(removeelem);
1965     }
1966   }
1967 }
1968
1969 //================================================================================
1970 /*!
1971  * \brief Replace elemToRm by elemToAdd in the all groups
1972  */
1973 //================================================================================
1974
1975 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1976                                             const SMDS_MeshElement* elemToAdd,
1977                                             SMESHDS_Mesh *          aMesh)
1978 {
1979   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1980   if (!groups.empty()) {
1981     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1982     for ( ; grIt != groups.end(); grIt++ ) {
1983       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1984       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1985         group->SMDSGroup().Add( elemToAdd );
1986     }
1987   }
1988 }
1989
1990 //================================================================================
1991 /*!
1992  * \brief Replace elemToRm by elemToAdd in the all groups
1993  */
1994 //================================================================================
1995
1996 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1997                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1998                                             SMESHDS_Mesh *                         aMesh)
1999 {
2000   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2001   if (!groups.empty())
2002   {
2003     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2004     for ( ; grIt != groups.end(); grIt++ ) {
2005       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2006       if ( group && group->SMDSGroup().Remove( elemToRm ) )
2007         for ( int i = 0; i < elemToAdd.size(); ++i )
2008           group->SMDSGroup().Add( elemToAdd[ i ] );
2009     }
2010   }
2011 }
2012
2013 //=======================================================================
2014 //function : QuadToTri
2015 //purpose  : Cut quadrangles into triangles.
2016 //           theCrit is used to select a diagonal to cut
2017 //=======================================================================
2018
2019 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
2020                                   const bool         the13Diag)
2021 {
2022   myLastCreatedElems.Clear();
2023   myLastCreatedNodes.Clear();
2024
2025   MESSAGE( "::QuadToTri()" );
2026
2027   SMESHDS_Mesh * aMesh = GetMeshDS();
2028
2029   Handle(Geom_Surface) surface;
2030   SMESH_MesherHelper   helper( *GetMesh() );
2031
2032   TIDSortedElemSet::iterator itElem;
2033   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2034     const SMDS_MeshElement* elem = *itElem;
2035     if ( !elem || elem->GetType() != SMDSAbs_Face )
2036       continue;
2037     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
2038     if(!isquad) continue;
2039
2040     if(elem->NbNodes()==4) {
2041       // retrieve element nodes
2042       const SMDS_MeshNode* aNodes [4];
2043       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2044       int i = 0;
2045       while ( itN->more() )
2046         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2047
2048       int aShapeId = FindShape( elem );
2049       const SMDS_MeshElement* newElem1 = 0;
2050       const SMDS_MeshElement* newElem2 = 0;
2051       if ( the13Diag ) {
2052         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
2053         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
2054       }
2055       else {
2056         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
2057         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
2058       }
2059       myLastCreatedElems.Append(newElem1);
2060       myLastCreatedElems.Append(newElem2);
2061       // put a new triangle on the same shape and add to the same groups
2062       if ( aShapeId )
2063         {
2064           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2065           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2066         }
2067       AddToSameGroups( newElem1, elem, aMesh );
2068       AddToSameGroups( newElem2, elem, aMesh );
2069       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
2070       aMesh->RemoveElement( elem );
2071     }
2072
2073     // Quadratic quadrangle
2074
2075     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
2076
2077       // get surface elem is on
2078       int aShapeId = FindShape( elem );
2079       if ( aShapeId != helper.GetSubShapeID() ) {
2080         surface.Nullify();
2081         TopoDS_Shape shape;
2082         if ( aShapeId > 0 )
2083           shape = aMesh->IndexToShape( aShapeId );
2084         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
2085           TopoDS_Face face = TopoDS::Face( shape );
2086           surface = BRep_Tool::Surface( face );
2087           if ( !surface.IsNull() )
2088             helper.SetSubShape( shape );
2089         }
2090       }
2091
2092       const SMDS_MeshNode* aNodes [8];
2093       const SMDS_MeshNode* inFaceNode = 0;
2094       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2095       int i = 0;
2096       while ( itN->more() ) {
2097         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2098         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
2099              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
2100         {
2101           inFaceNode = aNodes[ i-1 ];
2102         }
2103       }
2104
2105       // find middle point for (0,1,2,3)
2106       // and create a node in this point;
2107       gp_XYZ p( 0,0,0 );
2108       if ( surface.IsNull() ) {
2109         for(i=0; i<4; i++)
2110           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
2111         p /= 4;
2112       }
2113       else {
2114         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
2115         gp_XY uv( 0,0 );
2116         for(i=0; i<4; i++)
2117           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
2118         uv /= 4.;
2119         p = surface->Value( uv.X(), uv.Y() ).XYZ();
2120       }
2121       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
2122       myLastCreatedNodes.Append(newN);
2123
2124       // create a new element
2125       const SMDS_MeshElement* newElem1 = 0;
2126       const SMDS_MeshElement* newElem2 = 0;
2127       if ( the13Diag ) {
2128         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
2129                                   aNodes[6], aNodes[7], newN );
2130         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
2131                                   newN,      aNodes[4], aNodes[5] );
2132       }
2133       else {
2134         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
2135                                   aNodes[7], aNodes[4], newN );
2136         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
2137                                   newN,      aNodes[5], aNodes[6] );
2138       }
2139       myLastCreatedElems.Append(newElem1);
2140       myLastCreatedElems.Append(newElem2);
2141       // put a new triangle on the same shape and add to the same groups
2142       if ( aShapeId )
2143         {
2144           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2145           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2146         }
2147       AddToSameGroups( newElem1, elem, aMesh );
2148       AddToSameGroups( newElem2, elem, aMesh );
2149       aMesh->RemoveElement( elem );
2150     }
2151   }
2152
2153   return true;
2154 }
2155
2156 //=======================================================================
2157 //function : getAngle
2158 //purpose  :
2159 //=======================================================================
2160
2161 double getAngle(const SMDS_MeshElement * tr1,
2162                 const SMDS_MeshElement * tr2,
2163                 const SMDS_MeshNode *    n1,
2164                 const SMDS_MeshNode *    n2)
2165 {
2166   double angle = 2. * M_PI; // bad angle
2167
2168   // get normals
2169   SMESH::Controls::TSequenceOfXYZ P1, P2;
2170   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2171        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2172     return angle;
2173   gp_Vec N1,N2;
2174   if(!tr1->IsQuadratic())
2175     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2176   else
2177     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2178   if ( N1.SquareMagnitude() <= gp::Resolution() )
2179     return angle;
2180   if(!tr2->IsQuadratic())
2181     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2182   else
2183     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2184   if ( N2.SquareMagnitude() <= gp::Resolution() )
2185     return angle;
2186
2187   // find the first diagonal node n1 in the triangles:
2188   // take in account a diagonal link orientation
2189   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2190   for ( int t = 0; t < 2; t++ ) {
2191     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2192     int i = 0, iDiag = -1;
2193     while ( it->more()) {
2194       const SMDS_MeshElement *n = it->next();
2195       if ( n == n1 || n == n2 ) {
2196         if ( iDiag < 0)
2197           iDiag = i;
2198         else {
2199           if ( i - iDiag == 1 )
2200             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2201           else
2202             nFirst[ t ] = n;
2203           break;
2204         }
2205       }
2206       i++;
2207     }
2208   }
2209   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2210     N2.Reverse();
2211
2212   angle = N1.Angle( N2 );
2213   //SCRUTE( angle );
2214   return angle;
2215 }
2216
2217 // =================================================
2218 // class generating a unique ID for a pair of nodes
2219 // and able to return nodes by that ID
2220 // =================================================
2221 class LinkID_Gen {
2222 public:
2223
2224   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2225     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2226   {}
2227
2228   long GetLinkID (const SMDS_MeshNode * n1,
2229                   const SMDS_MeshNode * n2) const
2230   {
2231     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2232   }
2233
2234   bool GetNodes (const long             theLinkID,
2235                  const SMDS_MeshNode* & theNode1,
2236                  const SMDS_MeshNode* & theNode2) const
2237   {
2238     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2239     if ( !theNode1 ) return false;
2240     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2241     if ( !theNode2 ) return false;
2242     return true;
2243   }
2244
2245 private:
2246   LinkID_Gen();
2247   const SMESHDS_Mesh* myMesh;
2248   long                myMaxID;
2249 };
2250
2251
2252 //=======================================================================
2253 //function : TriToQuad
2254 //purpose  : Fuse neighbour triangles into quadrangles.
2255 //           theCrit is used to select a neighbour to fuse with.
2256 //           theMaxAngle is a max angle between element normals at which
2257 //           fusion is still performed.
2258 //=======================================================================
2259
2260 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2261                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2262                                   const double                         theMaxAngle)
2263 {
2264   myLastCreatedElems.Clear();
2265   myLastCreatedNodes.Clear();
2266
2267   MESSAGE( "::TriToQuad()" );
2268
2269   if ( !theCrit.get() )
2270     return false;
2271
2272   SMESHDS_Mesh * aMesh = GetMeshDS();
2273
2274   // Prepare data for algo: build
2275   // 1. map of elements with their linkIDs
2276   // 2. map of linkIDs with their elements
2277
2278   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2279   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2280   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2281   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2282
2283   TIDSortedElemSet::iterator itElem;
2284   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2285     const SMDS_MeshElement* elem = *itElem;
2286     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2287     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2288     if(!IsTria) continue;
2289
2290     // retrieve element nodes
2291     const SMDS_MeshNode* aNodes [4];
2292     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2293     int i = 0;
2294     while ( i<3 )
2295       aNodes[ i++ ] = cast2Node( itN->next() );
2296     aNodes[ 3 ] = aNodes[ 0 ];
2297
2298     // fill maps
2299     for ( i = 0; i < 3; i++ ) {
2300       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2301       // check if elements sharing a link can be fused
2302       itLE = mapLi_listEl.find( link );
2303       if ( itLE != mapLi_listEl.end() ) {
2304         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2305           continue;
2306         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2307         //if ( FindShape( elem ) != FindShape( elem2 ))
2308         //  continue; // do not fuse triangles laying on different shapes
2309         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2310           continue; // avoid making badly shaped quads
2311         (*itLE).second.push_back( elem );
2312       }
2313       else {
2314         mapLi_listEl[ link ].push_back( elem );
2315       }
2316       mapEl_setLi [ elem ].insert( link );
2317     }
2318   }
2319   // Clean the maps from the links shared by a sole element, ie
2320   // links to which only one element is bound in mapLi_listEl
2321
2322   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2323     int nbElems = (*itLE).second.size();
2324     if ( nbElems < 2  ) {
2325       const SMDS_MeshElement* elem = (*itLE).second.front();
2326       SMESH_TLink link = (*itLE).first;
2327       mapEl_setLi[ elem ].erase( link );
2328       if ( mapEl_setLi[ elem ].empty() )
2329         mapEl_setLi.erase( elem );
2330     }
2331   }
2332
2333   // Algo: fuse triangles into quadrangles
2334
2335   while ( ! mapEl_setLi.empty() ) {
2336     // Look for the start element:
2337     // the element having the least nb of shared links
2338     const SMDS_MeshElement* startElem = 0;
2339     int minNbLinks = 4;
2340     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2341       int nbLinks = (*itEL).second.size();
2342       if ( nbLinks < minNbLinks ) {
2343         startElem = (*itEL).first;
2344         minNbLinks = nbLinks;
2345         if ( minNbLinks == 1 )
2346           break;
2347       }
2348     }
2349
2350     // search elements to fuse starting from startElem or links of elements
2351     // fused earlyer - startLinks
2352     list< SMESH_TLink > startLinks;
2353     while ( startElem || !startLinks.empty() ) {
2354       while ( !startElem && !startLinks.empty() ) {
2355         // Get an element to start, by a link
2356         SMESH_TLink linkId = startLinks.front();
2357         startLinks.pop_front();
2358         itLE = mapLi_listEl.find( linkId );
2359         if ( itLE != mapLi_listEl.end() ) {
2360           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2361           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2362           for ( ; itE != listElem.end() ; itE++ )
2363             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2364               startElem = (*itE);
2365           mapLi_listEl.erase( itLE );
2366         }
2367       }
2368
2369       if ( startElem ) {
2370         // Get candidates to be fused
2371         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2372         const SMESH_TLink *link12, *link13;
2373         startElem = 0;
2374         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2375         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2376         ASSERT( !setLi.empty() );
2377         set< SMESH_TLink >::iterator itLi;
2378         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2379         {
2380           const SMESH_TLink & link = (*itLi);
2381           itLE = mapLi_listEl.find( link );
2382           if ( itLE == mapLi_listEl.end() )
2383             continue;
2384
2385           const SMDS_MeshElement* elem = (*itLE).second.front();
2386           if ( elem == tr1 )
2387             elem = (*itLE).second.back();
2388           mapLi_listEl.erase( itLE );
2389           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2390             continue;
2391           if ( tr2 ) {
2392             tr3 = elem;
2393             link13 = &link;
2394           }
2395           else {
2396             tr2 = elem;
2397             link12 = &link;
2398           }
2399
2400           // add other links of elem to list of links to re-start from
2401           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2402           set< SMESH_TLink >::iterator it;
2403           for ( it = links.begin(); it != links.end(); it++ ) {
2404             const SMESH_TLink& link2 = (*it);
2405             if ( link2 != link )
2406               startLinks.push_back( link2 );
2407           }
2408         }
2409
2410         // Get nodes of possible quadrangles
2411         const SMDS_MeshNode *n12 [4], *n13 [4];
2412         bool Ok12 = false, Ok13 = false;
2413         const SMDS_MeshNode *linkNode1, *linkNode2;
2414         if(tr2) {
2415           linkNode1 = link12->first;
2416           linkNode2 = link12->second;
2417           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2418             Ok12 = true;
2419         }
2420         if(tr3) {
2421           linkNode1 = link13->first;
2422           linkNode2 = link13->second;
2423           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2424             Ok13 = true;
2425         }
2426
2427         // Choose a pair to fuse
2428         if ( Ok12 && Ok13 ) {
2429           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2430           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2431           double aBadRate12 = getBadRate( &quad12, theCrit );
2432           double aBadRate13 = getBadRate( &quad13, theCrit );
2433           if (  aBadRate13 < aBadRate12 )
2434             Ok12 = false;
2435           else
2436             Ok13 = false;
2437         }
2438
2439         // Make quadrangles
2440         // and remove fused elems and removed links from the maps
2441         mapEl_setLi.erase( tr1 );
2442         if ( Ok12 ) {
2443           mapEl_setLi.erase( tr2 );
2444           mapLi_listEl.erase( *link12 );
2445           if(tr1->NbNodes()==3) {
2446             const SMDS_MeshElement* newElem = 0;
2447             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2448             myLastCreatedElems.Append(newElem);
2449             AddToSameGroups( newElem, tr1, aMesh );
2450             int aShapeId = tr1->getshapeId();
2451             if ( aShapeId )
2452               {
2453                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2454               }
2455             aMesh->RemoveElement( tr1 );
2456             aMesh->RemoveElement( tr2 );
2457           }
2458           else {
2459             const SMDS_MeshNode* N1 [6];
2460             const SMDS_MeshNode* N2 [6];
2461             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2462             // now we receive following N1 and N2 (using numeration as above image)
2463             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2464             // i.e. first nodes from both arrays determ new diagonal
2465             const SMDS_MeshNode* aNodes[8];
2466             aNodes[0] = N1[0];
2467             aNodes[1] = N1[1];
2468             aNodes[2] = N2[0];
2469             aNodes[3] = N2[1];
2470             aNodes[4] = N1[3];
2471             aNodes[5] = N2[5];
2472             aNodes[6] = N2[3];
2473             aNodes[7] = N1[5];
2474             const SMDS_MeshElement* newElem = 0;
2475             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2476                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2477             myLastCreatedElems.Append(newElem);
2478             AddToSameGroups( newElem, tr1, aMesh );
2479             int aShapeId = tr1->getshapeId();
2480             if ( aShapeId )
2481               {
2482                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2483               }
2484             aMesh->RemoveElement( tr1 );
2485             aMesh->RemoveElement( tr2 );
2486             // remove middle node (9)
2487             GetMeshDS()->RemoveNode( N1[4] );
2488           }
2489         }
2490         else if ( Ok13 ) {
2491           mapEl_setLi.erase( tr3 );
2492           mapLi_listEl.erase( *link13 );
2493           if(tr1->NbNodes()==3) {
2494             const SMDS_MeshElement* newElem = 0;
2495             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2496             myLastCreatedElems.Append(newElem);
2497             AddToSameGroups( newElem, tr1, aMesh );
2498             int aShapeId = tr1->getshapeId();
2499             if ( aShapeId )
2500               {
2501                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2502               }
2503             aMesh->RemoveElement( tr1 );
2504             aMesh->RemoveElement( tr3 );
2505           }
2506           else {
2507             const SMDS_MeshNode* N1 [6];
2508             const SMDS_MeshNode* N2 [6];
2509             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2510             // now we receive following N1 and N2 (using numeration as above image)
2511             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2512             // i.e. first nodes from both arrays determ new diagonal
2513             const SMDS_MeshNode* aNodes[8];
2514             aNodes[0] = N1[0];
2515             aNodes[1] = N1[1];
2516             aNodes[2] = N2[0];
2517             aNodes[3] = N2[1];
2518             aNodes[4] = N1[3];
2519             aNodes[5] = N2[5];
2520             aNodes[6] = N2[3];
2521             aNodes[7] = N1[5];
2522             const SMDS_MeshElement* newElem = 0;
2523             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2524                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2525             myLastCreatedElems.Append(newElem);
2526             AddToSameGroups( newElem, tr1, aMesh );
2527             int aShapeId = tr1->getshapeId();
2528             if ( aShapeId )
2529               {
2530                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2531               }
2532             aMesh->RemoveElement( tr1 );
2533             aMesh->RemoveElement( tr3 );
2534             // remove middle node (9)
2535             GetMeshDS()->RemoveNode( N1[4] );
2536           }
2537         }
2538
2539         // Next element to fuse: the rejected one
2540         if ( tr3 )
2541           startElem = Ok12 ? tr3 : tr2;
2542
2543       } // if ( startElem )
2544     } // while ( startElem || !startLinks.empty() )
2545   } // while ( ! mapEl_setLi.empty() )
2546
2547   return true;
2548 }
2549
2550
2551 /*#define DUMPSO(txt) \
2552 //  cout << txt << endl;
2553 //=============================================================================
2554 //
2555 //
2556 //
2557 //=============================================================================
2558 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2559 {
2560 if ( i1 == i2 )
2561 return;
2562 int tmp = idNodes[ i1 ];
2563 idNodes[ i1 ] = idNodes[ i2 ];
2564 idNodes[ i2 ] = tmp;
2565 gp_Pnt Ptmp = P[ i1 ];
2566 P[ i1 ] = P[ i2 ];
2567 P[ i2 ] = Ptmp;
2568 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2569 }
2570
2571 //=======================================================================
2572 //function : SortQuadNodes
2573 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2574 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2575 //           1 or 2 else 0.
2576 //=======================================================================
2577
2578 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2579 int               idNodes[] )
2580 {
2581   gp_Pnt P[4];
2582   int i;
2583   for ( i = 0; i < 4; i++ ) {
2584     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2585     if ( !n ) return 0;
2586     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2587   }
2588
2589   gp_Vec V1(P[0], P[1]);
2590   gp_Vec V2(P[0], P[2]);
2591   gp_Vec V3(P[0], P[3]);
2592
2593   gp_Vec Cross1 = V1 ^ V2;
2594   gp_Vec Cross2 = V2 ^ V3;
2595
2596   i = 0;
2597   if (Cross1.Dot(Cross2) < 0)
2598   {
2599     Cross1 = V2 ^ V1;
2600     Cross2 = V1 ^ V3;
2601
2602     if (Cross1.Dot(Cross2) < 0)
2603       i = 2;
2604     else
2605       i = 1;
2606     swap ( i, i + 1, idNodes, P );
2607
2608     //     for ( int ii = 0; ii < 4; ii++ ) {
2609     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2610     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2611     //     }
2612   }
2613   return i;
2614 }
2615
2616 //=======================================================================
2617 //function : SortHexaNodes
2618 //purpose  : Set 8 nodes of a hexahedron in a good order.
2619 //           Return success status
2620 //=======================================================================
2621
2622 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2623                                       int               idNodes[] )
2624 {
2625   gp_Pnt P[8];
2626   int i;
2627   DUMPSO( "INPUT: ========================================");
2628   for ( i = 0; i < 8; i++ ) {
2629     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2630     if ( !n ) return false;
2631     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2632     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2633   }
2634   DUMPSO( "========================================");
2635
2636
2637   set<int> faceNodes;  // ids of bottom face nodes, to be found
2638   set<int> checkedId1; // ids of tried 2-nd nodes
2639   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2640   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2641   int iMin, iLoop1 = 0;
2642
2643   // Loop to try the 2-nd nodes
2644
2645   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2646   {
2647     // Find not checked 2-nd node
2648     for ( i = 1; i < 8; i++ )
2649       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2650         int id1 = idNodes[i];
2651         swap ( 1, i, idNodes, P );
2652         checkedId1.insert ( id1 );
2653         break;
2654       }
2655
2656     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2657     // ie that all but meybe one (id3 which is on the same face) nodes
2658     // lay on the same side from the triangle plane.
2659
2660     bool manyInPlane = false; // more than 4 nodes lay in plane
2661     int iLoop2 = 0;
2662     while ( ++iLoop2 < 6 ) {
2663
2664       // get 1-2-3 plane coeffs
2665       Standard_Real A, B, C, D;
2666       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2667       if ( N.SquareMagnitude() > gp::Resolution() )
2668       {
2669         gp_Pln pln ( P[0], N );
2670         pln.Coefficients( A, B, C, D );
2671
2672         // find the node (iMin) closest to pln
2673         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2674         set<int> idInPln;
2675         for ( i = 3; i < 8; i++ ) {
2676           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2677           if ( fabs( dist[i] ) < minDist ) {
2678             minDist = fabs( dist[i] );
2679             iMin = i;
2680           }
2681           if ( fabs( dist[i] ) <= tol )
2682             idInPln.insert( idNodes[i] );
2683         }
2684
2685         // there should not be more than 4 nodes in bottom plane
2686         if ( idInPln.size() > 1 )
2687         {
2688           DUMPSO( "### idInPln.size() = " << idInPln.size());
2689           // idInPlane does not contain the first 3 nodes
2690           if ( manyInPlane || idInPln.size() == 5)
2691             return false; // all nodes in one plane
2692           manyInPlane = true;
2693
2694           // set the 1-st node to be not in plane
2695           for ( i = 3; i < 8; i++ ) {
2696             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2697               DUMPSO( "### Reset 0-th node");
2698               swap( 0, i, idNodes, P );
2699               break;
2700             }
2701           }
2702
2703           // reset to re-check second nodes
2704           leastDist = DBL_MAX;
2705           faceNodes.clear();
2706           checkedId1.clear();
2707           iLoop1 = 0;
2708           break; // from iLoop2;
2709         }
2710
2711         // check that the other 4 nodes are on the same side
2712         bool sameSide = true;
2713         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2714         for ( i = 3; sameSide && i < 8; i++ ) {
2715           if ( i != iMin )
2716             sameSide = ( isNeg == dist[i] <= 0.);
2717         }
2718
2719         // keep best solution
2720         if ( sameSide && minDist < leastDist ) {
2721           leastDist = minDist;
2722           faceNodes.clear();
2723           faceNodes.insert( idNodes[ 1 ] );
2724           faceNodes.insert( idNodes[ 2 ] );
2725           faceNodes.insert( idNodes[ iMin ] );
2726           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2727                   << " leastDist = " << leastDist);
2728           if ( leastDist <= DBL_MIN )
2729             break;
2730         }
2731       }
2732
2733       // set next 3-d node to check
2734       int iNext = 2 + iLoop2;
2735       if ( iNext < 8 ) {
2736         DUMPSO( "Try 2-nd");
2737         swap ( 2, iNext, idNodes, P );
2738       }
2739     } // while ( iLoop2 < 6 )
2740   } // iLoop1
2741
2742   if ( faceNodes.empty() ) return false;
2743
2744   // Put the faceNodes in proper places
2745   for ( i = 4; i < 8; i++ ) {
2746     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2747       // find a place to put
2748       int iTo = 1;
2749       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2750         iTo++;
2751       DUMPSO( "Set faceNodes");
2752       swap ( iTo, i, idNodes, P );
2753     }
2754   }
2755
2756
2757   // Set nodes of the found bottom face in good order
2758   DUMPSO( " Found bottom face: ");
2759   i = SortQuadNodes( theMesh, idNodes );
2760   if ( i ) {
2761     gp_Pnt Ptmp = P[ i ];
2762     P[ i ] = P[ i+1 ];
2763     P[ i+1 ] = Ptmp;
2764   }
2765   //   else
2766   //     for ( int ii = 0; ii < 4; ii++ ) {
2767   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2768   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2769   //    }
2770
2771   // Gravity center of the top and bottom faces
2772   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2773   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2774
2775   // Get direction from the bottom to the top face
2776   gp_Vec upDir ( aGCb, aGCt );
2777   Standard_Real upDirSize = upDir.Magnitude();
2778   if ( upDirSize <= gp::Resolution() ) return false;
2779   upDir / upDirSize;
2780
2781   // Assure that the bottom face normal points up
2782   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2783   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2784   if ( Nb.Dot( upDir ) < 0 ) {
2785     DUMPSO( "Reverse bottom face");
2786     swap( 1, 3, idNodes, P );
2787   }
2788
2789   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2790   Standard_Real minDist = DBL_MAX;
2791   for ( i = 4; i < 8; i++ ) {
2792     // projection of P[i] to the plane defined by P[0] and upDir
2793     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2794     Standard_Real sqDist = P[0].SquareDistance( Pp );
2795     if ( sqDist < minDist ) {
2796       minDist = sqDist;
2797       iMin = i;
2798     }
2799   }
2800   DUMPSO( "Set 4-th");
2801   swap ( 4, iMin, idNodes, P );
2802
2803   // Set nodes of the top face in good order
2804   DUMPSO( "Sort top face");
2805   i = SortQuadNodes( theMesh, &idNodes[4] );
2806   if ( i ) {
2807     i += 4;
2808     gp_Pnt Ptmp = P[ i ];
2809     P[ i ] = P[ i+1 ];
2810     P[ i+1 ] = Ptmp;
2811   }
2812
2813   // Assure that direction of the top face normal is from the bottom face
2814   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2815   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2816   if ( Nt.Dot( upDir ) < 0 ) {
2817     DUMPSO( "Reverse top face");
2818     swap( 5, 7, idNodes, P );
2819   }
2820
2821   //   DUMPSO( "OUTPUT: ========================================");
2822   //   for ( i = 0; i < 8; i++ ) {
2823   //     float *p = ugrid->GetPoint(idNodes[i]);
2824   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2825   //   }
2826
2827   return true;
2828 }*/
2829
2830 //================================================================================
2831 /*!
2832  * \brief Return nodes linked to the given one
2833  * \param theNode - the node
2834  * \param linkedNodes - the found nodes
2835  * \param type - the type of elements to check
2836  *
2837  * Medium nodes are ignored
2838  */
2839 //================================================================================
2840
2841 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2842                                        TIDSortedElemSet &   linkedNodes,
2843                                        SMDSAbs_ElementType  type )
2844 {
2845   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2846   while ( elemIt->more() )
2847   {
2848     const SMDS_MeshElement* elem = elemIt->next();
2849     if(elem->GetType() == SMDSAbs_0DElement)
2850       continue;
2851     
2852     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2853     if ( elem->GetType() == SMDSAbs_Volume )
2854     {
2855       SMDS_VolumeTool vol( elem );
2856       while ( nodeIt->more() ) {
2857         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2858         if ( theNode != n && vol.IsLinked( theNode, n ))
2859           linkedNodes.insert( n );
2860       }
2861     }
2862     else
2863     {
2864       for ( int i = 0; nodeIt->more(); ++i ) {
2865         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2866         if ( n == theNode ) {
2867           int iBefore = i - 1;
2868           int iAfter  = i + 1;
2869           if ( elem->IsQuadratic() ) {
2870             int nb = elem->NbNodes() / 2;
2871             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2872             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2873           }
2874           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2875           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2876         }
2877       }
2878     }
2879   }
2880 }
2881
2882 //=======================================================================
2883 //function : laplacianSmooth
2884 //purpose  : pulls theNode toward the center of surrounding nodes directly
2885 //           connected to that node along an element edge
2886 //=======================================================================
2887
2888 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2889                      const Handle(Geom_Surface)&          theSurface,
2890                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2891 {
2892   // find surrounding nodes
2893
2894   TIDSortedElemSet nodeSet;
2895   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2896
2897   // compute new coodrs
2898
2899   double coord[] = { 0., 0., 0. };
2900   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2901   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2902     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2903     if ( theSurface.IsNull() ) { // smooth in 3D
2904       coord[0] += node->X();
2905       coord[1] += node->Y();
2906       coord[2] += node->Z();
2907     }
2908     else { // smooth in 2D
2909       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2910       gp_XY* uv = theUVMap[ node ];
2911       coord[0] += uv->X();
2912       coord[1] += uv->Y();
2913     }
2914   }
2915   int nbNodes = nodeSet.size();
2916   if ( !nbNodes )
2917     return;
2918   coord[0] /= nbNodes;
2919   coord[1] /= nbNodes;
2920
2921   if ( !theSurface.IsNull() ) {
2922     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2923     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2924     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2925     coord[0] = p3d.X();
2926     coord[1] = p3d.Y();
2927     coord[2] = p3d.Z();
2928   }
2929   else
2930     coord[2] /= nbNodes;
2931
2932   // move node
2933
2934   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2935 }
2936
2937 //=======================================================================
2938 //function : centroidalSmooth
2939 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2940 //           surrounding elements
2941 //=======================================================================
2942
2943 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2944                       const Handle(Geom_Surface)&          theSurface,
2945                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2946 {
2947   gp_XYZ aNewXYZ(0.,0.,0.);
2948   SMESH::Controls::Area anAreaFunc;
2949   double totalArea = 0.;
2950   int nbElems = 0;
2951
2952   // compute new XYZ
2953
2954   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2955   while ( elemIt->more() )
2956   {
2957     const SMDS_MeshElement* elem = elemIt->next();
2958     nbElems++;
2959
2960     gp_XYZ elemCenter(0.,0.,0.);
2961     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2962     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2963     int nn = elem->NbNodes();
2964     if(elem->IsQuadratic()) nn = nn/2;
2965     int i=0;
2966     //while ( itN->more() ) {
2967     while ( i<nn ) {
2968       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2969       i++;
2970       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2971       aNodePoints.push_back( aP );
2972       if ( !theSurface.IsNull() ) { // smooth in 2D
2973         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2974         gp_XY* uv = theUVMap[ aNode ];
2975         aP.SetCoord( uv->X(), uv->Y(), 0. );
2976       }
2977       elemCenter += aP;
2978     }
2979     double elemArea = anAreaFunc.GetValue( aNodePoints );
2980     totalArea += elemArea;
2981     elemCenter /= nn;
2982     aNewXYZ += elemCenter * elemArea;
2983   }
2984   aNewXYZ /= totalArea;
2985   if ( !theSurface.IsNull() ) {
2986     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2987     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2988   }
2989
2990   // move node
2991
2992   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2993 }
2994
2995 //=======================================================================
2996 //function : getClosestUV
2997 //purpose  : return UV of closest projection
2998 //=======================================================================
2999
3000 static bool getClosestUV (Extrema_GenExtPS& projector,
3001                           const gp_Pnt&     point,
3002                           gp_XY &           result)
3003 {
3004   projector.Perform( point );
3005   if ( projector.IsDone() ) {
3006     double u, v, minVal = DBL_MAX;
3007     for ( int i = projector.NbExt(); i > 0; i-- )
3008 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
3009       if ( projector.SquareDistance( i ) < minVal ) {
3010         minVal = projector.SquareDistance( i );
3011 #else
3012       if ( projector.Value( i ) < minVal ) {
3013         minVal = projector.Value( i );
3014 #endif
3015         projector.Point( i ).Parameter( u, v );
3016       }
3017     result.SetCoord( u, v );
3018     return true;
3019   }
3020   return false;
3021 }
3022
3023 //=======================================================================
3024 //function : Smooth
3025 //purpose  : Smooth theElements during theNbIterations or until a worst
3026 //           element has aspect ratio <= theTgtAspectRatio.
3027 //           Aspect Ratio varies in range [1.0, inf].
3028 //           If theElements is empty, the whole mesh is smoothed.
3029 //           theFixedNodes contains additionally fixed nodes. Nodes built
3030 //           on edges and boundary nodes are always fixed.
3031 //=======================================================================
3032
3033 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
3034                                set<const SMDS_MeshNode*> & theFixedNodes,
3035                                const SmoothMethod          theSmoothMethod,
3036                                const int                   theNbIterations,
3037                                double                      theTgtAspectRatio,
3038                                const bool                  the2D)
3039 {
3040   myLastCreatedElems.Clear();
3041   myLastCreatedNodes.Clear();
3042
3043   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
3044
3045   if ( theTgtAspectRatio < 1.0 )
3046     theTgtAspectRatio = 1.0;
3047
3048   const double disttol = 1.e-16;
3049
3050   SMESH::Controls::AspectRatio aQualityFunc;
3051
3052   SMESHDS_Mesh* aMesh = GetMeshDS();
3053
3054   if ( theElems.empty() ) {
3055     // add all faces to theElems
3056     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
3057     while ( fIt->more() ) {
3058       const SMDS_MeshElement* face = fIt->next();
3059       theElems.insert( face );
3060     }
3061   }
3062   // get all face ids theElems are on
3063   set< int > faceIdSet;
3064   TIDSortedElemSet::iterator itElem;
3065   if ( the2D )
3066     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3067       int fId = FindShape( *itElem );
3068       // check that corresponding submesh exists and a shape is face
3069       if (fId &&
3070           faceIdSet.find( fId ) == faceIdSet.end() &&
3071           aMesh->MeshElements( fId )) {
3072         TopoDS_Shape F = aMesh->IndexToShape( fId );
3073         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
3074           faceIdSet.insert( fId );
3075       }
3076     }
3077   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
3078
3079   // ===============================================
3080   // smooth elements on each TopoDS_Face separately
3081   // ===============================================
3082
3083   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
3084   for ( ; fId != faceIdSet.rend(); ++fId ) {
3085     // get face surface and submesh
3086     Handle(Geom_Surface) surface;
3087     SMESHDS_SubMesh* faceSubMesh = 0;
3088     TopoDS_Face face;
3089     double fToler2 = 0, f,l;
3090     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
3091     bool isUPeriodic = false, isVPeriodic = false;
3092     if ( *fId ) {
3093       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
3094       surface = BRep_Tool::Surface( face );
3095       faceSubMesh = aMesh->MeshElements( *fId );
3096       fToler2 = BRep_Tool::Tolerance( face );
3097       fToler2 *= fToler2 * 10.;
3098       isUPeriodic = surface->IsUPeriodic();
3099       if ( isUPeriodic )
3100         surface->UPeriod();
3101       isVPeriodic = surface->IsVPeriodic();
3102       if ( isVPeriodic )
3103         surface->VPeriod();
3104       surface->Bounds( u1, u2, v1, v2 );
3105     }
3106     // ---------------------------------------------------------
3107     // for elements on a face, find movable and fixed nodes and
3108     // compute UV for them
3109     // ---------------------------------------------------------
3110     bool checkBoundaryNodes = false;
3111     bool isQuadratic = false;
3112     set<const SMDS_MeshNode*> setMovableNodes;
3113     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3114     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3115     list< const SMDS_MeshElement* > elemsOnFace;
3116
3117     Extrema_GenExtPS projector;
3118     GeomAdaptor_Surface surfAdaptor;
3119     if ( !surface.IsNull() ) {
3120       surfAdaptor.Load( surface );
3121       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3122     }
3123     int nbElemOnFace = 0;
3124     itElem = theElems.begin();
3125     // loop on not yet smoothed elements: look for elems on a face
3126     while ( itElem != theElems.end() ) {
3127       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3128         break; // all elements found
3129
3130       const SMDS_MeshElement* elem = *itElem;
3131       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3132            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3133         ++itElem;
3134         continue;
3135       }
3136       elemsOnFace.push_back( elem );
3137       theElems.erase( itElem++ );
3138       nbElemOnFace++;
3139
3140       if ( !isQuadratic )
3141         isQuadratic = elem->IsQuadratic();
3142
3143       // get movable nodes of elem
3144       const SMDS_MeshNode* node;
3145       SMDS_TypeOfPosition posType;
3146       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3147       int nn = 0, nbn =  elem->NbNodes();
3148       if(elem->IsQuadratic())
3149         nbn = nbn/2;
3150       while ( nn++ < nbn ) {
3151         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3152         const SMDS_PositionPtr& pos = node->GetPosition();
3153         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3154         if (posType != SMDS_TOP_EDGE &&
3155             posType != SMDS_TOP_VERTEX &&
3156             theFixedNodes.find( node ) == theFixedNodes.end())
3157         {
3158           // check if all faces around the node are on faceSubMesh
3159           // because a node on edge may be bound to face
3160           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3161           bool all = true;
3162           if ( faceSubMesh ) {
3163             while ( eIt->more() && all ) {
3164               const SMDS_MeshElement* e = eIt->next();
3165               all = faceSubMesh->Contains( e );
3166             }
3167           }
3168           if ( all )
3169             setMovableNodes.insert( node );
3170           else
3171             checkBoundaryNodes = true;
3172         }
3173         if ( posType == SMDS_TOP_3DSPACE )
3174           checkBoundaryNodes = true;
3175       }
3176
3177       if ( surface.IsNull() )
3178         continue;
3179
3180       // get nodes to check UV
3181       list< const SMDS_MeshNode* > uvCheckNodes;
3182       itN = elem->nodesIterator();
3183       nn = 0; nbn =  elem->NbNodes();
3184       if(elem->IsQuadratic())
3185         nbn = nbn/2;
3186       while ( nn++ < nbn ) {
3187         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3188         if ( uvMap.find( node ) == uvMap.end() )
3189           uvCheckNodes.push_back( node );
3190         // add nodes of elems sharing node
3191         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3192         //         while ( eIt->more() ) {
3193         //           const SMDS_MeshElement* e = eIt->next();
3194         //           if ( e != elem ) {
3195         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3196         //             while ( nIt->more() ) {
3197         //               const SMDS_MeshNode* n =
3198         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3199         //               if ( uvMap.find( n ) == uvMap.end() )
3200         //                 uvCheckNodes.push_back( n );
3201         //             }
3202         //           }
3203         //         }
3204       }
3205       // check UV on face
3206       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3207       for ( ; n != uvCheckNodes.end(); ++n ) {
3208         node = *n;
3209         gp_XY uv( 0, 0 );
3210         const SMDS_PositionPtr& pos = node->GetPosition();
3211         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3212         // get existing UV
3213         switch ( posType ) {
3214         case SMDS_TOP_FACE: {
3215           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3216           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3217           break;
3218         }
3219         case SMDS_TOP_EDGE: {
3220           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3221           Handle(Geom2d_Curve) pcurve;
3222           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3223             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3224           if ( !pcurve.IsNull() ) {
3225             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3226             uv = pcurve->Value( u ).XY();
3227           }
3228           break;
3229         }
3230         case SMDS_TOP_VERTEX: {
3231           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3232           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3233             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3234           break;
3235         }
3236         default:;
3237         }
3238         // check existing UV
3239         bool project = true;
3240         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3241         double dist1 = DBL_MAX, dist2 = 0;
3242         if ( posType != SMDS_TOP_3DSPACE ) {
3243           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3244           project = dist1 > fToler2;
3245         }
3246         if ( project ) { // compute new UV
3247           gp_XY newUV;
3248           if ( !getClosestUV( projector, pNode, newUV )) {
3249             MESSAGE("Node Projection Failed " << node);
3250           }
3251           else {
3252             if ( isUPeriodic )
3253               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3254             if ( isVPeriodic )
3255               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3256             // check new UV
3257             if ( posType != SMDS_TOP_3DSPACE )
3258               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3259             if ( dist2 < dist1 )
3260               uv = newUV;
3261           }
3262         }
3263         // store UV in the map
3264         listUV.push_back( uv );
3265         uvMap.insert( make_pair( node, &listUV.back() ));
3266       }
3267     } // loop on not yet smoothed elements
3268
3269     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3270       checkBoundaryNodes = true;
3271
3272     // fix nodes on mesh boundary
3273
3274     if ( checkBoundaryNodes ) {
3275       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3276       map< SMESH_TLink, int >::iterator link_nb;
3277       // put all elements links to linkNbMap
3278       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3279       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3280         const SMDS_MeshElement* elem = (*elemIt);
3281         int nbn =  elem->NbCornerNodes();
3282         // loop on elem links: insert them in linkNbMap
3283         for ( int iN = 0; iN < nbn; ++iN ) {
3284           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3285           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3286           SMESH_TLink link( n1, n2 );
3287           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3288           link_nb->second++;
3289         }
3290       }
3291       // remove nodes that are in links encountered only once from setMovableNodes
3292       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3293         if ( link_nb->second == 1 ) {
3294           setMovableNodes.erase( link_nb->first.node1() );
3295           setMovableNodes.erase( link_nb->first.node2() );
3296         }
3297       }
3298     }
3299
3300     // -----------------------------------------------------
3301     // for nodes on seam edge, compute one more UV ( uvMap2 );
3302     // find movable nodes linked to nodes on seam and which
3303     // are to be smoothed using the second UV ( uvMap2 )
3304     // -----------------------------------------------------
3305
3306     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3307     if ( !surface.IsNull() ) {
3308       TopExp_Explorer eExp( face, TopAbs_EDGE );
3309       for ( ; eExp.More(); eExp.Next() ) {
3310         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3311         if ( !BRep_Tool::IsClosed( edge, face ))
3312           continue;
3313         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3314         if ( !sm ) continue;
3315         // find out which parameter varies for a node on seam
3316         double f,l;
3317         gp_Pnt2d uv1, uv2;
3318         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3319         if ( pcurve.IsNull() ) continue;
3320         uv1 = pcurve->Value( f );
3321         edge.Reverse();
3322         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3323         if ( pcurve.IsNull() ) continue;
3324         uv2 = pcurve->Value( f );
3325         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3326         // assure uv1 < uv2
3327         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3328           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3329         }
3330         // get nodes on seam and its vertices
3331         list< const SMDS_MeshNode* > seamNodes;
3332         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3333         while ( nSeamIt->more() ) {
3334           const SMDS_MeshNode* node = nSeamIt->next();
3335           if ( !isQuadratic || !IsMedium( node ))
3336             seamNodes.push_back( node );
3337         }
3338         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3339         for ( ; vExp.More(); vExp.Next() ) {
3340           sm = aMesh->MeshElements( vExp.Current() );
3341           if ( sm ) {
3342             nSeamIt = sm->GetNodes();
3343             while ( nSeamIt->more() )
3344               seamNodes.push_back( nSeamIt->next() );
3345           }
3346         }
3347         // loop on nodes on seam
3348         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3349         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3350           const SMDS_MeshNode* nSeam = *noSeIt;
3351           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3352           if ( n_uv == uvMap.end() )
3353             continue;
3354           // set the first UV
3355           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3356           // set the second UV
3357           listUV.push_back( *n_uv->second );
3358           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3359           if ( uvMap2.empty() )
3360             uvMap2 = uvMap; // copy the uvMap contents
3361           uvMap2[ nSeam ] = &listUV.back();
3362
3363           // collect movable nodes linked to ones on seam in nodesNearSeam
3364           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3365           while ( eIt->more() ) {
3366             const SMDS_MeshElement* e = eIt->next();
3367             int nbUseMap1 = 0, nbUseMap2 = 0;
3368             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3369             int nn = 0, nbn =  e->NbNodes();
3370             if(e->IsQuadratic()) nbn = nbn/2;
3371             while ( nn++ < nbn )
3372             {
3373               const SMDS_MeshNode* n =
3374                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3375               if (n == nSeam ||
3376                   setMovableNodes.find( n ) == setMovableNodes.end() )
3377                 continue;
3378               // add only nodes being closer to uv2 than to uv1
3379               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3380                            0.5 * ( n->Y() + nSeam->Y() ),
3381                            0.5 * ( n->Z() + nSeam->Z() ));
3382               gp_XY uv;
3383               getClosestUV( projector, pMid, uv );
3384               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3385                 nodesNearSeam.insert( n );
3386                 nbUseMap2++;
3387               }
3388               else
3389                 nbUseMap1++;
3390             }
3391             // for centroidalSmooth all element nodes must
3392             // be on one side of a seam
3393             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3394               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3395               nn = 0;
3396               while ( nn++ < nbn ) {
3397                 const SMDS_MeshNode* n =
3398                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3399                 setMovableNodes.erase( n );
3400               }
3401             }
3402           }
3403         } // loop on nodes on seam
3404       } // loop on edge of a face
3405     } // if ( !face.IsNull() )
3406
3407     if ( setMovableNodes.empty() ) {
3408       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3409       continue; // goto next face
3410     }
3411
3412     // -------------
3413     // SMOOTHING //
3414     // -------------
3415
3416     int it = -1;
3417     double maxRatio = -1., maxDisplacement = -1.;
3418     set<const SMDS_MeshNode*>::iterator nodeToMove;
3419     for ( it = 0; it < theNbIterations; it++ ) {
3420       maxDisplacement = 0.;
3421       nodeToMove = setMovableNodes.begin();
3422       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3423         const SMDS_MeshNode* node = (*nodeToMove);
3424         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3425
3426         // smooth
3427         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3428         if ( theSmoothMethod == LAPLACIAN )
3429           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3430         else
3431           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3432
3433         // node displacement
3434         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3435         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3436         if ( aDispl > maxDisplacement )
3437           maxDisplacement = aDispl;
3438       }
3439       // no node movement => exit
3440       //if ( maxDisplacement < 1.e-16 ) {
3441       if ( maxDisplacement < disttol ) {
3442         MESSAGE("-- no node movement --");
3443         break;
3444       }
3445
3446       // check elements quality
3447       maxRatio  = 0;
3448       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3449       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3450         const SMDS_MeshElement* elem = (*elemIt);
3451         if ( !elem || elem->GetType() != SMDSAbs_Face )
3452           continue;
3453         SMESH::Controls::TSequenceOfXYZ aPoints;
3454         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3455           double aValue = aQualityFunc.GetValue( aPoints );
3456           if ( aValue > maxRatio )
3457             maxRatio = aValue;
3458         }
3459       }
3460       if ( maxRatio <= theTgtAspectRatio ) {
3461         MESSAGE("-- quality achived --");
3462         break;
3463       }
3464       if (it+1 == theNbIterations) {
3465         MESSAGE("-- Iteration limit exceeded --");
3466       }
3467     } // smoothing iterations
3468
3469     MESSAGE(" Face id: " << *fId <<
3470             " Nb iterstions: " << it <<
3471             " Displacement: " << maxDisplacement <<
3472             " Aspect Ratio " << maxRatio);
3473
3474     // ---------------------------------------
3475     // new nodes positions are computed,
3476     // record movement in DS and set new UV
3477     // ---------------------------------------
3478     nodeToMove = setMovableNodes.begin();
3479     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3480       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3481       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3482       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3483       if ( node_uv != uvMap.end() ) {
3484         gp_XY* uv = node_uv->second;
3485         node->SetPosition
3486           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3487       }
3488     }
3489
3490     // move medium nodes of quadratic elements
3491     if ( isQuadratic )
3492     {
3493       SMESH_MesherHelper helper( *GetMesh() );
3494       if ( !face.IsNull() )
3495         helper.SetSubShape( face );
3496       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3497       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3498         const SMDS_VtkFace* QF =
3499           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3500         if(QF && QF->IsQuadratic()) {
3501           vector<const SMDS_MeshNode*> Ns;
3502           Ns.reserve(QF->NbNodes()+1);
3503           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3504           while ( anIter->more() )
3505             Ns.push_back( cast2Node(anIter->next()) );
3506           Ns.push_back( Ns[0] );
3507           double x, y, z;
3508           for(int i=0; i<QF->NbNodes(); i=i+2) {
3509             if ( !surface.IsNull() ) {
3510               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3511               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3512               gp_XY uv = ( uv1 + uv2 ) / 2.;
3513               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3514               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3515             }
3516             else {
3517               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3518               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3519               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3520             }
3521             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3522                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3523                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3524               // we have to move i+1 node
3525               aMesh->MoveNode( Ns[i+1], x, y, z );
3526             }
3527           }
3528         }
3529       }
3530     }
3531
3532   } // loop on face ids
3533
3534 }
3535
3536 //=======================================================================
3537 //function : isReverse
3538 //purpose  : Return true if normal of prevNodes is not co-directied with
3539 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3540 //           iNotSame is where prevNodes and nextNodes are different.
3541 //           If result is true then future volume orientation is OK
3542 //=======================================================================
3543
3544 static bool isReverse(const SMDS_MeshElement*             face,
3545                       const vector<const SMDS_MeshNode*>& prevNodes,
3546                       const vector<const SMDS_MeshNode*>& nextNodes,
3547                       const int                           iNotSame)
3548 {
3549
3550   SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
3551   SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
3552   gp_XYZ extrDir( pN - pP ), faceNorm;
3553   SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false );
3554
3555   return faceNorm * extrDir < 0.0;
3556 }
3557
3558 //=======================================================================
3559 /*!
3560  * \brief Create elements by sweeping an element
3561  * \param elem - element to sweep
3562  * \param newNodesItVec - nodes generated from each node of the element
3563  * \param newElems - generated elements
3564  * \param nbSteps - number of sweeping steps
3565  * \param srcElements - to append elem for each generated element
3566  */
3567 //=======================================================================
3568
3569 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3570                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3571                                     list<const SMDS_MeshElement*>&        newElems,
3572                                     const int                             nbSteps,
3573                                     SMESH_SequenceOfElemPtr&              srcElements)
3574 {
3575   //MESSAGE("sweepElement " << nbSteps);
3576   SMESHDS_Mesh* aMesh = GetMeshDS();
3577
3578   const int           nbNodes = elem->NbNodes();          
3579   const int         nbCorners = elem->NbCornerNodes();
3580   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of 
3581                                                           polyhedron creation !!! */
3582   // Loop on elem nodes:
3583   // find new nodes and detect same nodes indices
3584   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3585   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3586   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3587   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3588
3589   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
3590   vector<int> sames(nbNodes);
3591   vector<bool> isSingleNode(nbNodes);
3592
3593   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3594     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
3595     const SMDS_MeshNode*                         node = nnIt->first;
3596     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3597     if ( listNewNodes.empty() )
3598       return;
3599
3600     itNN   [ iNode ] = listNewNodes.begin();
3601     prevNod[ iNode ] = node;
3602     nextNod[ iNode ] = listNewNodes.front();
3603
3604     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
3605                                                              corner node of linear */
3606     if ( prevNod[ iNode ] != nextNod [ iNode ])
3607       nbDouble += !isSingleNode[iNode];
3608
3609     if( iNode < nbCorners ) { // check corners only
3610       if ( prevNod[ iNode ] == nextNod [ iNode ])
3611         sames[nbSame++] = iNode;
3612       else
3613         iNotSameNode = iNode;
3614     }
3615   }
3616
3617   if ( nbSame == nbNodes || nbSame > 2) {
3618     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3619     return;
3620   }
3621
3622   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
3623   {
3624     // fix nodes order to have bottom normal external
3625     if ( baseType == SMDSEntity_Polygon )
3626     {
3627       std::reverse( itNN.begin(), itNN.end() );
3628       std::reverse( prevNod.begin(), prevNod.end() );
3629       std::reverse( midlNod.begin(), midlNod.end() );
3630       std::reverse( nextNod.begin(), nextNod.end() );
3631       std::reverse( isSingleNode.begin(), isSingleNode.end() );
3632     }
3633     else
3634     {
3635       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
3636       SMDS_MeshCell::applyInterlace( ind, itNN );
3637       SMDS_MeshCell::applyInterlace( ind, prevNod );
3638       SMDS_MeshCell::applyInterlace( ind, nextNod );
3639       SMDS_MeshCell::applyInterlace( ind, midlNod );
3640       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3641       if ( nbSame > 0 )
3642       {
3643         sames[nbSame] = iNotSameNode;
3644         for ( int j = 0; j <= nbSame; ++j )
3645           for ( size_t i = 0; i < ind.size(); ++i )
3646             if ( ind[i] == sames[j] )
3647             {
3648               sames[j] = i;
3649               break;
3650             }
3651         iNotSameNode = sames[nbSame];
3652       }
3653     }
3654   }
3655
3656   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3657   if ( nbSame > 0 ) {
3658     iSameNode    = sames[ nbSame-1 ];
3659     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
3660     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
3661     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3662   }
3663
3664   // make new elements
3665   for (int iStep = 0; iStep < nbSteps; iStep++ )
3666   {
3667     // get next nodes
3668     for ( iNode = 0; iNode < nbNodes; iNode++ )
3669     {
3670       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
3671       nextNod[ iNode ] = *itNN[ iNode ]++;
3672     }
3673
3674     SMDS_MeshElement* aNewElem = 0;
3675     /*if(!elem->IsPoly())*/ {
3676       switch ( baseType ) {
3677       case SMDSEntity_0D:
3678       case SMDSEntity_Node: { // sweep NODE
3679         if ( nbSame == 0 ) {
3680           if ( isSingleNode[0] )
3681             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3682           else
3683             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3684         }
3685         else
3686           return;
3687         break;
3688       }
3689       case SMDSEntity_Edge: { // sweep EDGE
3690         if ( nbDouble == 0 )
3691         {
3692           if ( nbSame == 0 ) // ---> quadrangle
3693             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3694                                       nextNod[ 1 ], nextNod[ 0 ] );
3695           else               // ---> triangle
3696             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3697                                       nextNod[ iNotSameNode ] );
3698         }
3699         else                 // ---> polygon
3700         {
3701           vector<const SMDS_MeshNode*> poly_nodes;
3702           poly_nodes.push_back( prevNod[0] );
3703           poly_nodes.push_back( prevNod[1] );
3704           if ( prevNod[1] != nextNod[1] )
3705           {
3706             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
3707             poly_nodes.push_back( nextNod[1] );
3708           }
3709           if ( prevNod[0] != nextNod[0] )
3710           {
3711             poly_nodes.push_back( nextNod[0] );
3712             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
3713           }
3714           switch ( poly_nodes.size() ) {
3715           case 3:
3716             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
3717             break;
3718           case 4:
3719             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
3720                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
3721             break;
3722           default:
3723             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
3724           }
3725         }
3726         break;
3727       }
3728       case SMDSEntity_Triangle: // TRIANGLE --->
3729         {
3730           if ( nbDouble > 0 ) break;
3731           if ( nbSame == 0 )       // ---> pentahedron
3732             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3733                                          nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
3734
3735           else if ( nbSame == 1 )  // ---> pyramid
3736             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3737                                          nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3738                                          nextNod[ iSameNode ]);
3739
3740           else // 2 same nodes:       ---> tetrahedron
3741             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3742                                          nextNod[ iNotSameNode ]);
3743           break;
3744         }
3745       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
3746         {
3747           if ( nbSame == 2 )
3748             return;
3749           if ( nbDouble+nbSame == 2 )
3750           {
3751             if(nbSame==0) {      // ---> quadratic quadrangle
3752               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3753                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
3754             }
3755             else { //(nbSame==1) // ---> quadratic triangle
3756               if(sames[0]==2) {
3757                 return; // medium node on axis
3758               }
3759               else if(sames[0]==0)
3760                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3761                                           nextNod[2], midlNod[1], prevNod[2]);
3762               else // sames[0]==1
3763                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3764                                           midlNod[0], nextNod[2], prevNod[2]);
3765             }
3766           }
3767           else if ( nbDouble == 3 )
3768           {
3769             if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
3770               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3771                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
3772             }
3773           }
3774           else
3775             return;
3776           break;
3777         }
3778       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
3779         if ( nbDouble > 0 ) break;
3780
3781         if ( nbSame == 0 )       // ---> hexahedron
3782           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
3783                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
3784
3785         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
3786           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3787                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3788                                        nextNod[ iSameNode ]);
3789           newElems.push_back( aNewElem );
3790           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
3791                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3792                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3793         }
3794         else if ( nbSame == 2 ) { // ---> pentahedron
3795           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3796             // iBeforeSame is same too
3797             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3798                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
3799                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3800           else
3801             // iAfterSame is same too
3802             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
3803                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3804                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3805         }
3806         break;
3807       }
3808       case SMDSEntity_Quad_Triangle: { // sweep Quadratic TRIANGLE --->
3809         if ( nbDouble+nbSame != 3 ) break;
3810         if(nbSame==0) {
3811           // --->  pentahedron with 15 nodes
3812           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3813                                        nextNod[0], nextNod[1], nextNod[2],
3814                                        prevNod[3], prevNod[4], prevNod[5],
3815                                        nextNod[3], nextNod[4], nextNod[5],
3816                                        midlNod[0], midlNod[1], midlNod[2]);
3817         }
3818         else if(nbSame==1) {
3819           // --->  2d order pyramid of 13 nodes
3820           int apex = iSameNode;
3821           int i0 = ( apex + 1 ) % nbCorners;
3822           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
3823           int i0a = apex + 3;
3824           int i1a = i1 + 3;
3825           int i01 = i0 + 3;
3826           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
3827                                       nextNod[i0], nextNod[i1], prevNod[apex],
3828                                       prevNod[i01], midlNod[i0],
3829                                       nextNod[i01], midlNod[i1],
3830                                       prevNod[i1a], prevNod[i0a],
3831                                       nextNod[i0a], nextNod[i1a]);
3832         }
3833         else if(nbSame==2) {
3834           // --->  2d order tetrahedron of 10 nodes
3835           int n1 = iNotSameNode;
3836           int n2 = ( n1 + 1             ) % nbCorners;
3837           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
3838           int n12 = n1 + 3;
3839           int n23 = n2 + 3;
3840           int n31 = n3 + 3;
3841           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3842                                        prevNod[n12], prevNod[n23], prevNod[n31],
3843                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3844         }
3845         break;
3846       }
3847       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
3848         if( nbSame == 0 ) {
3849           if ( nbDouble != 4 ) break;
3850           // --->  hexahedron with 20 nodes
3851           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3852                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3853                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3854                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3855                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3856         }
3857         else if(nbSame==1) {
3858           // ---> pyramid + pentahedron - can not be created since it is needed 
3859           // additional middle node at the center of face
3860           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3861           return;
3862         }
3863         else if( nbSame == 2 ) {
3864           if ( nbDouble != 2 ) break;
3865           // --->  2d order Pentahedron with 15 nodes
3866           int n1,n2,n4,n5;
3867           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3868             // iBeforeSame is same too
3869             n1 = iBeforeSame;
3870             n2 = iOpposSame;
3871             n4 = iSameNode;
3872             n5 = iAfterSame;
3873           }
3874           else {
3875             // iAfterSame is same too
3876             n1 = iSameNode;
3877             n2 = iBeforeSame;
3878             n4 = iAfterSame;
3879             n5 = iOpposSame;
3880           }
3881           int n12 = n2 + 4;
3882           int n45 = n4 + 4;
3883           int n14 = n1 + 4;
3884           int n25 = n5 + 4;
3885           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3886                                        prevNod[n4], prevNod[n5], nextNod[n5],
3887                                        prevNod[n12], midlNod[n2], nextNod[n12],
3888                                        prevNod[n45], midlNod[n5], nextNod[n45],
3889                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3890         }
3891         break;
3892       }
3893       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
3894
3895         if( nbSame == 0 && nbDouble == 9 ) {
3896           // --->  tri-quadratic hexahedron with 27 nodes
3897           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3898                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3899                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3900                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3901                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
3902                                        prevNod[8], // bottom center
3903                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
3904                                        nextNod[8], // top center
3905                                        midlNod[8]);// elem center
3906         }
3907         else
3908         {
3909           return;
3910         }
3911         break;
3912       }
3913       case SMDSEntity_Polygon: { // sweep POLYGON
3914
3915         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
3916           // --->  hexagonal prism
3917           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3918                                        prevNod[3], prevNod[4], prevNod[5],
3919                                        nextNod[0], nextNod[1], nextNod[2],
3920                                        nextNod[3], nextNod[4], nextNod[5]);
3921         }
3922         break;
3923       }
3924       default:
3925         break;
3926       }
3927     }
3928
3929     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
3930     {
3931       if ( baseType != SMDSEntity_Polygon )
3932       {
3933         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
3934         SMDS_MeshCell::applyInterlace( ind, prevNod );
3935         SMDS_MeshCell::applyInterlace( ind, nextNod );
3936         SMDS_MeshCell::applyInterlace( ind, midlNod );
3937         SMDS_MeshCell::applyInterlace( ind, itNN );
3938         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3939         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
3940       }
3941       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3942       vector<int> quantities (nbNodes + 2);
3943       polyedre_nodes.clear();
3944       quantities.clear();
3945
3946       // bottom of prism
3947       for (int inode = 0; inode < nbNodes; inode++)
3948         polyedre_nodes.push_back( prevNod[inode] );
3949       quantities.push_back( nbNodes );
3950
3951       // top of prism
3952       polyedre_nodes.push_back( nextNod[0] );
3953       for (int inode = nbNodes; inode-1; --inode )
3954         polyedre_nodes.push_back( nextNod[inode-1] );
3955       quantities.push_back( nbNodes );
3956
3957       // side faces
3958       for (int iface = 0; iface < nbNodes; iface++)
3959       {
3960         const int prevNbNodes = polyedre_nodes.size();
3961         int inextface = (iface+1) % nbNodes;
3962         polyedre_nodes.push_back( prevNod[inextface] );
3963         polyedre_nodes.push_back( prevNod[iface] );
3964         if ( prevNod[iface] != nextNod[iface] )
3965         {
3966           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
3967           polyedre_nodes.push_back( nextNod[iface] );
3968         }
3969         if ( prevNod[inextface] != nextNod[inextface] )
3970         {
3971           polyedre_nodes.push_back( nextNod[inextface] );
3972           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
3973         }
3974         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
3975         if ( nbFaceNodes > 2 )
3976           quantities.push_back( nbFaceNodes );
3977         else // degenerated face
3978           polyedre_nodes.resize( prevNbNodes );
3979       }
3980       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3981     }
3982
3983     if ( aNewElem ) {
3984       newElems.push_back( aNewElem );
3985       myLastCreatedElems.Append(aNewElem);
3986       srcElements.Append( elem );
3987     }
3988
3989     // set new prev nodes
3990     for ( iNode = 0; iNode < nbNodes; iNode++ )
3991       prevNod[ iNode ] = nextNod[ iNode ];
3992
3993   } // for steps
3994 }
3995
3996 //=======================================================================
3997 /*!
3998  * \brief Create 1D and 2D elements around swept elements
3999  * \param mapNewNodes - source nodes and ones generated from them
4000  * \param newElemsMap - source elements and ones generated from them
4001  * \param elemNewNodesMap - nodes generated from each node of each element
4002  * \param elemSet - all swept elements
4003  * \param nbSteps - number of sweeping steps
4004  * \param srcElements - to append elem for each generated element
4005  */
4006 //=======================================================================
4007
4008 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
4009                                   TElemOfElemListMap &     newElemsMap,
4010                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
4011                                   TIDSortedElemSet&        elemSet,
4012                                   const int                nbSteps,
4013                                   SMESH_SequenceOfElemPtr& srcElements)
4014 {
4015   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
4016   SMESHDS_Mesh* aMesh = GetMeshDS();
4017
4018   // Find nodes belonging to only one initial element - sweep them to get edges.
4019
4020   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
4021   for ( ; nList != mapNewNodes.end(); nList++ )
4022   {
4023     const SMDS_MeshNode* node =
4024       static_cast<const SMDS_MeshNode*>( nList->first );
4025     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
4026     int nbInitElems = 0;
4027     const SMDS_MeshElement* el = 0;
4028     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
4029     while ( eIt->more() && nbInitElems < 2 ) {
4030       el = eIt->next();
4031       SMDSAbs_ElementType type = el->GetType();
4032       if ( type == SMDSAbs_Volume || type < highType ) continue;
4033       if ( type > highType ) {
4034         nbInitElems = 0;
4035         highType = type;
4036       }
4037       nbInitElems += elemSet.count(el);
4038     }
4039     if ( nbInitElems < 2 ) {
4040       bool NotCreateEdge = el && el->IsMediumNode(node);
4041       if(!NotCreateEdge) {
4042         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
4043         list<const SMDS_MeshElement*> newEdges;
4044         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
4045       }
4046     }
4047   }
4048
4049   // Make a ceiling for each element ie an equal element of last new nodes.
4050   // Find free links of faces - make edges and sweep them into faces.
4051
4052   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
4053   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
4054   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
4055   {
4056     const SMDS_MeshElement* elem = itElem->first;
4057     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
4058
4059     if(itElem->second.size()==0) continue;
4060
4061     const bool isQuadratic = elem->IsQuadratic();
4062
4063     if ( elem->GetType() == SMDSAbs_Edge ) {
4064       // create a ceiling edge
4065       if ( !isQuadratic ) {
4066         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4067                                vecNewNodes[ 1 ]->second.back())) {
4068           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4069                                                    vecNewNodes[ 1 ]->second.back()));
4070           srcElements.Append( myLastCreatedElems.Last() );
4071         }
4072       }
4073       else {
4074         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4075                                vecNewNodes[ 1 ]->second.back(),
4076                                vecNewNodes[ 2 ]->second.back())) {
4077           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4078                                                    vecNewNodes[ 1 ]->second.back(),
4079                                                    vecNewNodes[ 2 ]->second.back()));
4080           srcElements.Append( myLastCreatedElems.Last() );
4081         }
4082       }
4083     }
4084     if ( elem->GetType() != SMDSAbs_Face )
4085       continue;
4086
4087     bool hasFreeLinks = false;
4088
4089     TIDSortedElemSet avoidSet;
4090     avoidSet.insert( elem );
4091
4092     set<const SMDS_MeshNode*> aFaceLastNodes;
4093     int iNode, nbNodes = vecNewNodes.size();
4094     if ( !isQuadratic ) {
4095       // loop on the face nodes
4096       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4097         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4098         // look for free links of the face
4099         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4100         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4101         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4102         // check if a link is free
4103         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4104           hasFreeLinks = true;
4105           // make an edge and a ceiling for a new edge
4106           if ( !aMesh->FindEdge( n1, n2 )) {
4107             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
4108             srcElements.Append( myLastCreatedElems.Last() );
4109           }
4110           n1 = vecNewNodes[ iNode ]->second.back();
4111           n2 = vecNewNodes[ iNext ]->second.back();
4112           if ( !aMesh->FindEdge( n1, n2 )) {
4113             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
4114             srcElements.Append( myLastCreatedElems.Last() );
4115           }
4116         }
4117       }
4118     }
4119     else { // elem is quadratic face
4120       int nbn = nbNodes/2;
4121       for ( iNode = 0; iNode < nbn; iNode++ ) {
4122         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4123         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4124         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4125         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4126         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4127         // check if a link is free
4128         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4129              ! SMESH_MeshEditor::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4130              ! SMESH_MeshEditor::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4131           hasFreeLinks = true;
4132           // make an edge and a ceiling for a new edge
4133           // find medium node
4134           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4135             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4136             srcElements.Append( myLastCreatedElems.Last() );
4137           }
4138           n1 = vecNewNodes[ iNode ]->second.back();
4139           n2 = vecNewNodes[ iNext ]->second.back();
4140           n3 = vecNewNodes[ iNode+nbn ]->second.back();
4141           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4142             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4143             srcElements.Append( myLastCreatedElems.Last() );
4144           }
4145         }
4146       }
4147       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4148         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4149       }
4150     }
4151
4152     // sweep free links into faces
4153
4154     if ( hasFreeLinks )  {
4155       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4156       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4157
4158       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4159       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4160         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4161         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4162       }
4163       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4164         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4165         std::advance( v, volNb );
4166         // find indices of free faces of a volume and their source edges
4167         list< int > freeInd;
4168         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4169         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4170         int iF, nbF = vTool.NbFaces();
4171         for ( iF = 0; iF < nbF; iF ++ ) {
4172           if (vTool.IsFreeFace( iF ) &&
4173               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4174               initNodeSet != faceNodeSet) // except an initial face
4175           {
4176             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4177               continue;
4178             freeInd.push_back( iF );
4179             // find source edge of a free face iF
4180             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4181             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4182             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4183                                    initNodeSet.begin(), initNodeSet.end(),
4184                                    commonNodes.begin());
4185             if ( (*v)->IsQuadratic() )
4186               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4187             else
4188               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4189 #ifdef _DEBUG_
4190             if ( !srcEdges.back() )
4191             {
4192               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4193                    << iF << " of volume #" << vTool.ID() << endl;
4194             }
4195 #endif
4196           }
4197         }
4198         if ( freeInd.empty() )
4199           continue;
4200
4201         // create faces for all steps;
4202         // if such a face has been already created by sweep of edge,
4203         // assure that its orientation is OK
4204         for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4205           vTool.Set( *v, /*ignoreCentralNodes=*/false );
4206           vTool.SetExternalNormal();
4207           const int nextShift = vTool.IsForward() ? +1 : -1;
4208           list< int >::iterator ind = freeInd.begin();
4209           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4210           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4211           {
4212             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4213             int nbn = vTool.NbFaceNodes( *ind );
4214             const SMDS_MeshElement * f = 0;
4215             if ( nbn == 3 )              ///// triangle
4216             {
4217               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4218               if ( !f ||
4219                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4220               {
4221                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4222                                                      nodes[ 1 ],
4223                                                      nodes[ 1 + nextShift ] };
4224                 if ( f )
4225                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4226                 else
4227                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4228                                                             newOrder[ 2 ] ));
4229               }
4230             }
4231             else if ( nbn == 4 )       ///// quadrangle
4232             {
4233               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4234               if ( !f ||
4235                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4236               {
4237                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4238                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
4239                 if ( f )
4240                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4241                 else
4242                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4243                                                             newOrder[ 2 ], newOrder[ 3 ]));
4244               }
4245             }
4246             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4247             {
4248               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4249               if ( !f ||
4250                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4251               {
4252                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4253                                                      nodes[2],
4254                                                      nodes[2 + 2*nextShift],
4255                                                      nodes[3 - 2*nextShift],
4256                                                      nodes[3],
4257                                                      nodes[3 + 2*nextShift]};
4258                 if ( f )
4259                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4260                 else
4261                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4262                                                             newOrder[ 1 ],
4263                                                             newOrder[ 2 ],
4264                                                             newOrder[ 3 ],
4265                                                             newOrder[ 4 ],
4266                                                             newOrder[ 5 ] ));
4267               }
4268             }
4269             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4270             {
4271               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4272                                    nodes[1], nodes[3], nodes[5], nodes[7] );
4273               if ( !f ||
4274                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4275               {
4276                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4277                                                      nodes[4 - 2*nextShift],
4278                                                      nodes[4],
4279                                                      nodes[4 + 2*nextShift],
4280                                                      nodes[1],
4281                                                      nodes[5 - 2*nextShift],
4282                                                      nodes[5],
4283                                                      nodes[5 + 2*nextShift] };
4284                 if ( f )
4285                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4286                 else
4287                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4288                                                            newOrder[ 2 ], newOrder[ 3 ],
4289                                                            newOrder[ 4 ], newOrder[ 5 ],
4290                                                            newOrder[ 6 ], newOrder[ 7 ]));
4291               }
4292             }
4293             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4294             {
4295               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4296                                       SMDSAbs_Face, /*noMedium=*/false);
4297               if ( !f ||
4298                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4299               {
4300                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
4301                                                      nodes[4 - 2*nextShift],
4302                                                      nodes[4],
4303                                                      nodes[4 + 2*nextShift],
4304                                                      nodes[1],
4305                                                      nodes[5 - 2*nextShift],
4306                                                      nodes[5],
4307                                                      nodes[5 + 2*nextShift],
4308                                                      nodes[8] };
4309                 if ( f )
4310                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4311                 else
4312                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4313                                                            newOrder[ 2 ], newOrder[ 3 ],
4314                                                            newOrder[ 4 ], newOrder[ 5 ],
4315                                                            newOrder[ 6 ], newOrder[ 7 ],
4316                                                            newOrder[ 8 ]));
4317               }
4318             }
4319             else  //////// polygon
4320             {
4321               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
4322               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4323               if ( !f ||
4324                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4325               {
4326                 if ( !vTool.IsForward() )
4327                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4328                 if ( f )
4329                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4330                 else
4331                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4332               }
4333             }
4334
4335             while ( srcElements.Length() < myLastCreatedElems.Length() )
4336               srcElements.Append( *srcEdge );
4337
4338           }  // loop on free faces
4339
4340           // go to the next volume
4341           iVol = 0;
4342           while ( iVol++ < nbVolumesByStep ) v++;
4343
4344         } // loop on steps
4345       } // loop on volumes of one step
4346     } // sweep free links into faces
4347
4348     // Make a ceiling face with a normal external to a volume
4349
4350     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
4351
4352     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4353     if ( iF >= 0 ) {
4354       lastVol.SetExternalNormal();
4355       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4356       int nbn = lastVol.NbFaceNodes( iF );
4357       if ( nbn == 3 ) {
4358         if (!hasFreeLinks ||
4359             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4360           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4361       }
4362       else if ( nbn == 4 )
4363       {
4364         if (!hasFreeLinks ||
4365             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4366           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]));
4367       }
4368       else if ( nbn == 6 && isQuadratic )
4369       {
4370         if (!hasFreeLinks ||
4371             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5]) )
4372           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4373                                                    nodes[1], nodes[3], nodes[5]));
4374       }
4375       else if ( nbn == 8 && isQuadratic )
4376       {
4377         if (!hasFreeLinks ||
4378             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4379                              nodes[1], nodes[3], nodes[5], nodes[7]) )
4380           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4381                                                    nodes[1], nodes[3], nodes[5], nodes[7]));
4382       }
4383       else if ( nbn == 9 && isQuadratic )
4384       {
4385         if (!hasFreeLinks ||
4386             !aMesh->FindElement(vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4387                                 SMDSAbs_Face, /*noMedium=*/false) )
4388           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4389                                                    nodes[1], nodes[3], nodes[5], nodes[7],
4390                                                    nodes[8]));
4391       }
4392       else {
4393         vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes + nbn );
4394         if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4395           myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4396       }
4397
4398       while ( srcElements.Length() < myLastCreatedElems.Length() )
4399         srcElements.Append( myLastCreatedElems.Last() );
4400     }
4401   } // loop on swept elements
4402 }
4403
4404 //=======================================================================
4405 //function : RotationSweep
4406 //purpose  :
4407 //=======================================================================
4408
4409 SMESH_MeshEditor::PGroupIDs
4410 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4411                                 const gp_Ax1&      theAxis,
4412                                 const double       theAngle,
4413                                 const int          theNbSteps,
4414                                 const double       theTol,
4415                                 const bool         theMakeGroups,
4416                                 const bool         theMakeWalls)
4417 {
4418   myLastCreatedElems.Clear();
4419   myLastCreatedNodes.Clear();
4420
4421   // source elements for each generated one
4422   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4423
4424   MESSAGE( "RotationSweep()");
4425   gp_Trsf aTrsf;
4426   aTrsf.SetRotation( theAxis, theAngle );
4427   gp_Trsf aTrsf2;
4428   aTrsf2.SetRotation( theAxis, theAngle/2. );
4429
4430   gp_Lin aLine( theAxis );
4431   double aSqTol = theTol * theTol;
4432
4433   SMESHDS_Mesh* aMesh = GetMeshDS();
4434
4435   TNodeOfNodeListMap mapNewNodes;
4436   TElemOfVecOfNnlmiMap mapElemNewNodes;
4437   TElemOfElemListMap newElemsMap;
4438
4439   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4440                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4441                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4442   // loop on theElems
4443   TIDSortedElemSet::iterator itElem;
4444   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4445     const SMDS_MeshElement* elem = *itElem;
4446     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4447       continue;
4448     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4449     newNodesItVec.reserve( elem->NbNodes() );
4450
4451     // loop on elem nodes
4452     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4453     while ( itN->more() )
4454     {
4455       // check if a node has been already sweeped
4456       const SMDS_MeshNode* node = cast2Node( itN->next() );
4457
4458       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4459       double coord[3];
4460       aXYZ.Coord( coord[0], coord[1], coord[2] );
4461       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4462
4463       TNodeOfNodeListMapItr nIt =
4464         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4465       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4466       if ( listNewNodes.empty() )
4467       {
4468         // check if we are to create medium nodes between corner ones
4469         bool needMediumNodes = false;
4470         if ( isQuadraticMesh )
4471         {
4472           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4473           while (it->more() && !needMediumNodes )
4474           {
4475             const SMDS_MeshElement* invElem = it->next();
4476             if ( invElem != elem && !theElems.count( invElem )) continue;
4477             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4478             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4479               needMediumNodes = true;
4480           }
4481         }
4482
4483         // make new nodes
4484         const SMDS_MeshNode * newNode = node;
4485         for ( int i = 0; i < theNbSteps; i++ ) {
4486           if ( !isOnAxis ) {
4487             if ( needMediumNodes )  // create a medium node
4488             {
4489               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4490               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4491               myLastCreatedNodes.Append(newNode);
4492               srcNodes.Append( node );
4493               listNewNodes.push_back( newNode );
4494               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4495             }
4496             else {
4497               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4498             }
4499             // create a corner node
4500             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4501             myLastCreatedNodes.Append(newNode);
4502             srcNodes.Append( node );
4503             listNewNodes.push_back( newNode );
4504           }
4505           else {
4506             listNewNodes.push_back( newNode );
4507             // if ( needMediumNodes )
4508             //   listNewNodes.push_back( newNode );
4509           }
4510         }
4511       }
4512       newNodesItVec.push_back( nIt );
4513     }
4514     // make new elements
4515     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4516   }
4517
4518   if ( theMakeWalls )
4519     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4520
4521   PGroupIDs newGroupIDs;
4522   if ( theMakeGroups )
4523     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4524
4525   return newGroupIDs;
4526 }
4527
4528
4529 //=======================================================================
4530 //function : CreateNode
4531 //purpose  :
4532 //=======================================================================
4533 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4534                                                   const double y,
4535                                                   const double z,
4536                                                   const double tolnode,
4537                                                   SMESH_SequenceOfNode& aNodes)
4538 {
4539   // myLastCreatedElems.Clear();
4540   // myLastCreatedNodes.Clear();
4541
4542   gp_Pnt P1(x,y,z);
4543   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4544
4545   // try to search in sequence of existing nodes
4546   // if aNodes.Length()>0 we 'nave to use given sequence
4547   // else - use all nodes of mesh
4548   if(aNodes.Length()>0) {
4549     int i;
4550     for(i=1; i<=aNodes.Length(); i++) {
4551       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4552       if(P1.Distance(P2)<tolnode)
4553         return aNodes.Value(i);
4554     }
4555   }
4556   else {
4557     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4558     while(itn->more()) {
4559       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4560       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4561       if(P1.Distance(P2)<tolnode)
4562         return aN;
4563     }
4564   }
4565
4566   // create new node and return it
4567   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4568   //myLastCreatedNodes.Append(NewNode);
4569   return NewNode;
4570 }
4571
4572
4573 //=======================================================================
4574 //function : ExtrusionSweep
4575 //purpose  :
4576 //=======================================================================
4577
4578 SMESH_MeshEditor::PGroupIDs
4579 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4580                                   const gp_Vec&       theStep,
4581                                   const int           theNbSteps,
4582                                   TElemOfElemListMap& newElemsMap,
4583                                   const bool          theMakeGroups,
4584                                   const int           theFlags,
4585                                   const double        theTolerance)
4586 {
4587   ExtrusParam aParams;
4588   aParams.myDir = gp_Dir(theStep);
4589   aParams.myNodes.Clear();
4590   aParams.mySteps = new TColStd_HSequenceOfReal;
4591   int i;
4592   for(i=1; i<=theNbSteps; i++)
4593     aParams.mySteps->Append(theStep.Magnitude());
4594
4595   return
4596     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4597 }
4598
4599
4600 //=======================================================================
4601 //function : ExtrusionSweep
4602 //purpose  :
4603 //=======================================================================
4604
4605 SMESH_MeshEditor::PGroupIDs
4606 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4607                                   ExtrusParam&        theParams,
4608                                   TElemOfElemListMap& newElemsMap,
4609                                   const bool          theMakeGroups,
4610                                   const int           theFlags,
4611                                   const double        theTolerance)
4612 {
4613   myLastCreatedElems.Clear();
4614   myLastCreatedNodes.Clear();
4615
4616   // source elements for each generated one
4617   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4618
4619   SMESHDS_Mesh* aMesh = GetMeshDS();
4620
4621   int nbsteps = theParams.mySteps->Length();
4622
4623   TNodeOfNodeListMap mapNewNodes;
4624   //TNodeOfNodeVecMap mapNewNodes;
4625   TElemOfVecOfNnlmiMap mapElemNewNodes;
4626   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4627
4628   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4629                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4630                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4631   // loop on theElems
4632   TIDSortedElemSet::iterator itElem;
4633   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4634     // check element type
4635     const SMDS_MeshElement* elem = *itElem;
4636     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4637       continue;
4638
4639     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4640     newNodesItVec.reserve( elem->NbNodes() );
4641
4642     // loop on elem nodes
4643     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4644     while ( itN->more() )
4645     {
4646       // check if a node has been already sweeped
4647       const SMDS_MeshNode* node = cast2Node( itN->next() );
4648       TNodeOfNodeListMap::iterator nIt =
4649         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4650       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4651       if ( listNewNodes.empty() )
4652       {
4653         // make new nodes
4654
4655         // check if we are to create medium nodes between corner ones
4656         bool needMediumNodes = false;
4657         if ( isQuadraticMesh )
4658         {
4659           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4660           while (it->more() && !needMediumNodes )
4661           {
4662             const SMDS_MeshElement* invElem = it->next();
4663             if ( invElem != elem && !theElems.count( invElem )) continue;
4664             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4665             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4666               needMediumNodes = true;
4667           }
4668         }
4669
4670         double coord[] = { node->X(), node->Y(), node->Z() };
4671         for ( int i = 0; i < nbsteps; i++ )
4672         {
4673           if ( needMediumNodes ) // create a medium node
4674           {
4675             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4676             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4677             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4678             if( theFlags & EXTRUSION_FLAG_SEW ) {
4679               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4680                                                          theTolerance, theParams.myNodes);
4681               listNewNodes.push_back( newNode );
4682             }
4683             else {
4684               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4685               myLastCreatedNodes.Append(newNode);
4686               srcNodes.Append( node );
4687               listNewNodes.push_back( newNode );
4688             }
4689           }
4690           // create a corner node
4691           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4692           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4693           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4694           if( theFlags & EXTRUSION_FLAG_SEW ) {
4695             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4696                                                        theTolerance, theParams.myNodes);
4697             listNewNodes.push_back( newNode );
4698           }
4699           else {
4700             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4701             myLastCreatedNodes.Append(newNode);
4702             srcNodes.Append( node );
4703             listNewNodes.push_back( newNode );
4704           }
4705         }
4706       }
4707       newNodesItVec.push_back( nIt );
4708     }
4709     // make new elements
4710     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4711   }
4712
4713   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4714     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4715   }
4716   PGroupIDs newGroupIDs;
4717   if ( theMakeGroups )
4718     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4719
4720   return newGroupIDs;
4721 }
4722
4723 //=======================================================================
4724 //function : ExtrusionAlongTrack
4725 //purpose  :
4726 //=======================================================================
4727 SMESH_MeshEditor::Extrusion_Error
4728 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4729                                        SMESH_subMesh*       theTrack,
4730                                        const SMDS_MeshNode* theN1,
4731                                        const bool           theHasAngles,
4732                                        list<double>&        theAngles,
4733                                        const bool           theLinearVariation,
4734                                        const bool           theHasRefPoint,
4735                                        const gp_Pnt&        theRefPoint,
4736                                        const bool           theMakeGroups)
4737 {
4738   MESSAGE("ExtrusionAlongTrack");
4739   myLastCreatedElems.Clear();
4740   myLastCreatedNodes.Clear();
4741
4742   int aNbE;
4743   std::list<double> aPrms;
4744   TIDSortedElemSet::iterator itElem;
4745
4746   gp_XYZ aGC;
4747   TopoDS_Edge aTrackEdge;
4748   TopoDS_Vertex aV1, aV2;
4749
4750   SMDS_ElemIteratorPtr aItE;
4751   SMDS_NodeIteratorPtr aItN;
4752   SMDSAbs_ElementType aTypeE;
4753
4754   TNodeOfNodeListMap mapNewNodes;
4755
4756   // 1. Check data
4757   aNbE = theElements.size();
4758   // nothing to do
4759   if ( !aNbE )
4760     return EXTR_NO_ELEMENTS;
4761
4762   // 1.1 Track Pattern
4763   ASSERT( theTrack );
4764
4765   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4766
4767   aItE = pSubMeshDS->GetElements();
4768   while ( aItE->more() ) {
4769     const SMDS_MeshElement* pE = aItE->next();
4770     aTypeE = pE->GetType();
4771     // Pattern must contain links only
4772     if ( aTypeE != SMDSAbs_Edge )
4773       return EXTR_PATH_NOT_EDGE;
4774   }
4775
4776   list<SMESH_MeshEditor_PathPoint> fullList;
4777
4778   const TopoDS_Shape& aS = theTrack->GetSubShape();
4779   // Sub-shape for the Pattern must be an Edge or Wire
4780   if( aS.ShapeType() == TopAbs_EDGE ) {
4781     aTrackEdge = TopoDS::Edge( aS );
4782     // the Edge must not be degenerated
4783     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4784       return EXTR_BAD_PATH_SHAPE;
4785     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4786     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4787     const SMDS_MeshNode* aN1 = aItN->next();
4788     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4789     const SMDS_MeshNode* aN2 = aItN->next();
4790     // starting node must be aN1 or aN2
4791     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4792       return EXTR_BAD_STARTING_NODE;
4793     aItN = pSubMeshDS->GetNodes();
4794     while ( aItN->more() ) {
4795       const SMDS_MeshNode* pNode = aItN->next();
4796       const SMDS_EdgePosition* pEPos =
4797         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4798       double aT = pEPos->GetUParameter();
4799       aPrms.push_back( aT );
4800     }
4801     //Extrusion_Error err =
4802     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4803   } else if( aS.ShapeType() == TopAbs_WIRE ) {
4804     list< SMESH_subMesh* > LSM;
4805     TopTools_SequenceOfShape Edges;
4806     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4807     while(itSM->more()) {
4808       SMESH_subMesh* SM = itSM->next();
4809       LSM.push_back(SM);
4810       const TopoDS_Shape& aS = SM->GetSubShape();
4811       Edges.Append(aS);
4812     }
4813     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4814     int startNid = theN1->GetID();
4815     TColStd_MapOfInteger UsedNums;
4816     
4817     int NbEdges = Edges.Length();
4818     int i = 1;
4819     for(; i<=NbEdges; i++) {
4820       int k = 0;
4821       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4822       for(; itLSM!=LSM.end(); itLSM++) {
4823         k++;
4824         if(UsedNums.Contains(k)) continue;
4825         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4826         SMESH_subMesh* locTrack = *itLSM;
4827         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4828         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4829         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4830         const SMDS_MeshNode* aN1 = aItN->next();
4831         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4832         const SMDS_MeshNode* aN2 = aItN->next();
4833         // starting node must be aN1 or aN2
4834         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4835         // 2. Collect parameters on the track edge
4836         aPrms.clear();
4837         aItN = locMeshDS->GetNodes();
4838         while ( aItN->more() ) {
4839           const SMDS_MeshNode* pNode = aItN->next();
4840           const SMDS_EdgePosition* pEPos =
4841             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4842           double aT = pEPos->GetUParameter();
4843           aPrms.push_back( aT );
4844         }
4845         list<SMESH_MeshEditor_PathPoint> LPP;
4846         //Extrusion_Error err =
4847         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4848         LLPPs.push_back(LPP);
4849         UsedNums.Add(k);
4850         // update startN for search following egde
4851         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4852         else startNid = aN1->GetID();
4853         break;
4854       }
4855     }
4856     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4857     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4858     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4859     for(; itPP!=firstList.end(); itPP++) {
4860       fullList.push_back( *itPP );
4861     }
4862     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4863     fullList.pop_back();
4864     itLLPP++;
4865     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4866       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4867       itPP = currList.begin();
4868       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4869       gp_Dir D1 = PP1.Tangent();
4870       gp_Dir D2 = PP2.Tangent();
4871       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4872                            (D1.Z()+D2.Z())/2 ) );
4873       PP1.SetTangent(Dnew);
4874       fullList.push_back(PP1);
4875       itPP++;
4876       for(; itPP!=firstList.end(); itPP++) {
4877         fullList.push_back( *itPP );
4878       }
4879       PP1 = fullList.back();
4880       fullList.pop_back();
4881     }
4882     // if wire not closed
4883     fullList.push_back(PP1);
4884     // else ???
4885   }
4886   else {
4887     return EXTR_BAD_PATH_SHAPE;
4888   }
4889
4890   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4891                           theHasRefPoint, theRefPoint, theMakeGroups);
4892 }
4893
4894
4895 //=======================================================================
4896 //function : ExtrusionAlongTrack
4897 //purpose  :
4898 //=======================================================================
4899 SMESH_MeshEditor::Extrusion_Error
4900 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4901                                        SMESH_Mesh*          theTrack,
4902                                        const SMDS_MeshNode* theN1,
4903                                        const bool           theHasAngles,
4904                                        list<double>&        theAngles,
4905                                        const bool           theLinearVariation,
4906                                        const bool           theHasRefPoint,
4907                                        const gp_Pnt&        theRefPoint,
4908                                        const bool           theMakeGroups)
4909 {
4910   myLastCreatedElems.Clear();
4911   myLastCreatedNodes.Clear();
4912
4913   int aNbE;
4914   std::list<double> aPrms;
4915   TIDSortedElemSet::iterator itElem;
4916
4917   gp_XYZ aGC;
4918   TopoDS_Edge aTrackEdge;
4919   TopoDS_Vertex aV1, aV2;
4920
4921   SMDS_ElemIteratorPtr aItE;
4922   SMDS_NodeIteratorPtr aItN;
4923   SMDSAbs_ElementType aTypeE;
4924
4925   TNodeOfNodeListMap mapNewNodes;
4926
4927   // 1. Check data
4928   aNbE = theElements.size();
4929   // nothing to do
4930   if ( !aNbE )
4931     return EXTR_NO_ELEMENTS;
4932
4933   // 1.1 Track Pattern
4934   ASSERT( theTrack );
4935
4936   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4937
4938   aItE = pMeshDS->elementsIterator();
4939   while ( aItE->more() ) {
4940     const SMDS_MeshElement* pE = aItE->next();
4941     aTypeE = pE->GetType();
4942     // Pattern must contain links only
4943     if ( aTypeE != SMDSAbs_Edge )
4944       return EXTR_PATH_NOT_EDGE;
4945   }
4946
4947   list<SMESH_MeshEditor_PathPoint> fullList;
4948
4949   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4950
4951   if( aS == SMESH_Mesh::PseudoShape() ) {
4952     //Mesh without shape
4953     const SMDS_MeshNode* currentNode = NULL;
4954     const SMDS_MeshNode* prevNode = theN1;
4955     std::vector<const SMDS_MeshNode*> aNodesList;
4956     aNodesList.push_back(theN1);
4957     int nbEdges = 0, conn=0;
4958     const SMDS_MeshElement* prevElem = NULL;
4959     const SMDS_MeshElement* currentElem = NULL;
4960     int totalNbEdges = theTrack->NbEdges();
4961     SMDS_ElemIteratorPtr nIt;
4962
4963     //check start node
4964     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
4965       return EXTR_BAD_STARTING_NODE;
4966     }
4967     
4968     conn = nbEdgeConnectivity(theN1);
4969     if(conn > 2)
4970       return EXTR_PATH_NOT_EDGE;
4971
4972     aItE = theN1->GetInverseElementIterator();
4973     prevElem = aItE->next();
4974     currentElem = prevElem;
4975     //Get all nodes
4976     if(totalNbEdges == 1 ) {
4977       nIt = currentElem->nodesIterator();
4978       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4979       if(currentNode == prevNode)
4980         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4981       aNodesList.push_back(currentNode);
4982     } else { 
4983       nIt = currentElem->nodesIterator();
4984       while( nIt->more() ) {
4985         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4986         if(currentNode == prevNode)
4987           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4988         aNodesList.push_back(currentNode);
4989         
4990         //case of the closed mesh
4991         if(currentNode == theN1) {
4992           nbEdges++;
4993           break;
4994         }
4995
4996         conn = nbEdgeConnectivity(currentNode);
4997         if(conn > 2) {
4998           return EXTR_PATH_NOT_EDGE;    
4999         }else if( conn == 1 && nbEdges > 0 ) {
5000           //End of the path
5001           nbEdges++;
5002           break;
5003         }else {
5004           prevNode = currentNode;
5005           aItE = currentNode->GetInverseElementIterator();
5006           currentElem = aItE->next();
5007           if( currentElem  == prevElem)
5008             currentElem = aItE->next();
5009           nIt = currentElem->nodesIterator();
5010           prevElem = currentElem;
5011           nbEdges++;
5012         }
5013       }
5014     } 
5015     
5016     if(nbEdges != totalNbEdges)
5017       return EXTR_PATH_NOT_EDGE;
5018
5019     TopTools_SequenceOfShape Edges;
5020     double x1,x2,y1,y2,z1,z2;
5021     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5022     int startNid = theN1->GetID();
5023     for(int i = 1; i < aNodesList.size(); i++) {
5024       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
5025       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
5026       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
5027       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));  
5028       list<SMESH_MeshEditor_PathPoint> LPP;
5029       aPrms.clear();
5030       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
5031       LLPPs.push_back(LPP);
5032       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
5033       else startNid = aNodesList[i-1]->GetID();
5034
5035     }
5036
5037     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5038     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5039     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5040     for(; itPP!=firstList.end(); itPP++) {
5041       fullList.push_back( *itPP );
5042     }
5043
5044     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5045     SMESH_MeshEditor_PathPoint PP2;
5046     fullList.pop_back();
5047     itLLPP++;
5048     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5049       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5050       itPP = currList.begin();
5051       PP2 = currList.front();
5052       gp_Dir D1 = PP1.Tangent();
5053       gp_Dir D2 = PP2.Tangent();
5054       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5055                            (D1.Z()+D2.Z())/2 ) );
5056       PP1.SetTangent(Dnew);
5057       fullList.push_back(PP1);
5058       itPP++;
5059       for(; itPP!=currList.end(); itPP++) {
5060         fullList.push_back( *itPP );
5061       }
5062       PP1 = fullList.back();
5063       fullList.pop_back();
5064     }
5065     fullList.push_back(PP1);
5066     
5067   } // Sub-shape for the Pattern must be an Edge or Wire
5068   else if( aS.ShapeType() == TopAbs_EDGE ) {
5069     aTrackEdge = TopoDS::Edge( aS );
5070     // the Edge must not be degenerated
5071     if ( BRep_Tool::Degenerated( aTrackEdge ) )
5072       return EXTR_BAD_PATH_SHAPE;
5073     TopExp::Vertices( aTrackEdge, aV1, aV2 );
5074     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
5075     const SMDS_MeshNode* aN1 = aItN->next();
5076     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
5077     const SMDS_MeshNode* aN2 = aItN->next();
5078     // starting node must be aN1 or aN2
5079     if ( !( aN1 == theN1 || aN2 == theN1 ) )
5080       return EXTR_BAD_STARTING_NODE;
5081     aItN = pMeshDS->nodesIterator();
5082     while ( aItN->more() ) {
5083       const SMDS_MeshNode* pNode = aItN->next();
5084       if( pNode==aN1 || pNode==aN2 ) continue;
5085       const SMDS_EdgePosition* pEPos =
5086         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5087       double aT = pEPos->GetUParameter();
5088       aPrms.push_back( aT );
5089     }
5090     //Extrusion_Error err =
5091     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5092   }
5093   else if( aS.ShapeType() == TopAbs_WIRE ) {
5094     list< SMESH_subMesh* > LSM;
5095     TopTools_SequenceOfShape Edges;
5096     TopExp_Explorer eExp(aS, TopAbs_EDGE);
5097     for(; eExp.More(); eExp.Next()) {
5098       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5099       if( BRep_Tool::Degenerated(E) ) continue;
5100       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5101       if(SM) {
5102         LSM.push_back(SM);
5103         Edges.Append(E);
5104       }
5105     }
5106     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5107     int startNid = theN1->GetID();
5108     TColStd_MapOfInteger UsedNums;
5109     int NbEdges = Edges.Length();
5110     int i = 1;
5111     for(; i<=NbEdges; i++) {
5112       int k = 0;
5113       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5114       for(; itLSM!=LSM.end(); itLSM++) {
5115         k++;
5116         if(UsedNums.Contains(k)) continue;
5117         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5118         SMESH_subMesh* locTrack = *itLSM;
5119         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5120         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5121         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5122         const SMDS_MeshNode* aN1 = aItN->next();
5123         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5124         const SMDS_MeshNode* aN2 = aItN->next();
5125         // starting node must be aN1 or aN2
5126         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
5127         // 2. Collect parameters on the track edge
5128         aPrms.clear();
5129         aItN = locMeshDS->GetNodes();
5130         while ( aItN->more() ) {
5131           const SMDS_MeshNode* pNode = aItN->next();
5132           const SMDS_EdgePosition* pEPos =
5133             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5134           double aT = pEPos->GetUParameter();
5135           aPrms.push_back( aT );
5136         }
5137         list<SMESH_MeshEditor_PathPoint> LPP;
5138         //Extrusion_Error err =
5139         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
5140         LLPPs.push_back(LPP);
5141         UsedNums.Add(k);
5142         // update startN for search following egde
5143         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
5144         else startNid = aN1->GetID();
5145         break;
5146       }
5147     }
5148     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5149     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5150     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5151     for(; itPP!=firstList.end(); itPP++) {
5152       fullList.push_back( *itPP );
5153     }
5154     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5155     fullList.pop_back();
5156     itLLPP++;
5157     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5158       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5159       itPP = currList.begin();
5160       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5161       gp_Dir D1 = PP1.Tangent();
5162       gp_Dir D2 = PP2.Tangent();
5163       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5164                            (D1.Z()+D2.Z())/2 ) );
5165       PP1.SetTangent(Dnew);
5166       fullList.push_back(PP1);
5167       itPP++;
5168       for(; itPP!=currList.end(); itPP++) {
5169         fullList.push_back( *itPP );
5170       }
5171       PP1 = fullList.back();
5172       fullList.pop_back();
5173     }
5174     // if wire not closed
5175     fullList.push_back(PP1);
5176     // else ???
5177   }
5178   else {
5179     return EXTR_BAD_PATH_SHAPE;
5180   }
5181
5182   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5183                           theHasRefPoint, theRefPoint, theMakeGroups);
5184 }
5185
5186
5187 //=======================================================================
5188 //function : MakeEdgePathPoints
5189 //purpose  : auxilary for ExtrusionAlongTrack
5190 //=======================================================================
5191 SMESH_MeshEditor::Extrusion_Error
5192 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5193                                      const TopoDS_Edge& aTrackEdge,
5194                                      bool FirstIsStart,
5195                                      list<SMESH_MeshEditor_PathPoint>& LPP)
5196 {
5197   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5198   aTolVec=1.e-7;
5199   aTolVec2=aTolVec*aTolVec;
5200   double aT1, aT2;
5201   TopoDS_Vertex aV1, aV2;
5202   TopExp::Vertices( aTrackEdge, aV1, aV2 );
5203   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5204   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5205   // 2. Collect parameters on the track edge
5206   aPrms.push_front( aT1 );
5207   aPrms.push_back( aT2 );
5208   // sort parameters
5209   aPrms.sort();
5210   if( FirstIsStart ) {
5211     if ( aT1 > aT2 ) {
5212       aPrms.reverse();
5213     }
5214   }
5215   else {
5216     if ( aT2 > aT1 ) {
5217       aPrms.reverse();
5218     }
5219   }
5220   // 3. Path Points
5221   SMESH_MeshEditor_PathPoint aPP;
5222   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5223   std::list<double>::iterator aItD = aPrms.begin();
5224   for(; aItD != aPrms.end(); ++aItD) {
5225     double aT = *aItD;
5226     gp_Pnt aP3D;
5227     gp_Vec aVec;
5228     aC3D->D1( aT, aP3D, aVec );
5229     aL2 = aVec.SquareMagnitude();
5230     if ( aL2 < aTolVec2 )
5231       return EXTR_CANT_GET_TANGENT;
5232     gp_Dir aTgt( aVec );
5233     aPP.SetPnt( aP3D );
5234     aPP.SetTangent( aTgt );
5235     aPP.SetParameter( aT );
5236     LPP.push_back(aPP);
5237   }
5238   return EXTR_OK;
5239 }
5240
5241
5242 //=======================================================================
5243 //function : MakeExtrElements
5244 //purpose  : auxilary for ExtrusionAlongTrack
5245 //=======================================================================
5246 SMESH_MeshEditor::Extrusion_Error
5247 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5248                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5249                                    const bool theHasAngles,
5250                                    list<double>& theAngles,
5251                                    const bool theLinearVariation,
5252                                    const bool theHasRefPoint,
5253                                    const gp_Pnt& theRefPoint,
5254                                    const bool theMakeGroups)
5255 {
5256   MESSAGE("MakeExtrElements");
5257   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5258   int aNbTP = fullList.size();
5259   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5260   // Angles
5261   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5262     LinearAngleVariation(aNbTP-1, theAngles);
5263   }
5264   vector<double> aAngles( aNbTP );
5265   int j = 0;
5266   for(; j<aNbTP; ++j) {
5267     aAngles[j] = 0.;
5268   }
5269   if ( theHasAngles ) {
5270     double anAngle;;
5271     std::list<double>::iterator aItD = theAngles.begin();
5272     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5273       anAngle = *aItD;
5274       aAngles[j] = anAngle;
5275     }
5276   }
5277   // fill vector of path points with angles
5278   //aPPs.resize(fullList.size());
5279   j = -1;
5280   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5281   for(; itPP!=fullList.end(); itPP++) {
5282     j++;
5283     SMESH_MeshEditor_PathPoint PP = *itPP;
5284     PP.SetAngle(aAngles[j]);
5285     aPPs[j] = PP;
5286   }
5287
5288   TNodeOfNodeListMap mapNewNodes;
5289   TElemOfVecOfNnlmiMap mapElemNewNodes;
5290   TElemOfElemListMap newElemsMap;
5291   TIDSortedElemSet::iterator itElem;
5292   double aX, aY, aZ;
5293   int aNb;
5294   SMDSAbs_ElementType aTypeE;
5295   // source elements for each generated one
5296   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5297
5298   // 3. Center of rotation aV0
5299   gp_Pnt aV0 = theRefPoint;
5300   gp_XYZ aGC;
5301   if ( !theHasRefPoint ) {
5302     aNb = 0;
5303     aGC.SetCoord( 0.,0.,0. );
5304
5305     itElem = theElements.begin();
5306     for ( ; itElem != theElements.end(); itElem++ ) {
5307       const SMDS_MeshElement* elem = *itElem;
5308
5309       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5310       while ( itN->more() ) {
5311         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5312         aX = node->X();
5313         aY = node->Y();
5314         aZ = node->Z();
5315
5316         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5317           list<const SMDS_MeshNode*> aLNx;
5318           mapNewNodes[node] = aLNx;
5319           //
5320           gp_XYZ aXYZ( aX, aY, aZ );
5321           aGC += aXYZ;
5322           ++aNb;
5323         }
5324       }
5325     }
5326     aGC /= aNb;
5327     aV0.SetXYZ( aGC );
5328   } // if (!theHasRefPoint) {
5329   mapNewNodes.clear();
5330
5331   // 4. Processing the elements
5332   SMESHDS_Mesh* aMesh = GetMeshDS();
5333
5334   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5335     // check element type
5336     const SMDS_MeshElement* elem = *itElem;
5337     aTypeE = elem->GetType();
5338     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5339       continue;
5340
5341     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5342     newNodesItVec.reserve( elem->NbNodes() );
5343
5344     // loop on elem nodes
5345     int nodeIndex = -1;
5346     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5347     while ( itN->more() )
5348     {
5349       ++nodeIndex;
5350       // check if a node has been already processed
5351       const SMDS_MeshNode* node =
5352         static_cast<const SMDS_MeshNode*>( itN->next() );
5353       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5354       if ( nIt == mapNewNodes.end() ) {
5355         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5356         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5357
5358         // make new nodes
5359         aX = node->X();  aY = node->Y(); aZ = node->Z();
5360
5361         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5362         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5363         gp_Ax1 anAx1, anAxT1T0;
5364         gp_Dir aDT1x, aDT0x, aDT1T0;
5365
5366         aTolAng=1.e-4;
5367
5368         aV0x = aV0;
5369         aPN0.SetCoord(aX, aY, aZ);
5370
5371         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5372         aP0x = aPP0.Pnt();
5373         aDT0x= aPP0.Tangent();
5374         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5375
5376         for ( j = 1; j < aNbTP; ++j ) {
5377           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5378           aP1x = aPP1.Pnt();
5379           aDT1x = aPP1.Tangent();
5380           aAngle1x = aPP1.Angle();
5381
5382           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5383           // Translation
5384           gp_Vec aV01x( aP0x, aP1x );
5385           aTrsf.SetTranslation( aV01x );
5386
5387           // traslated point
5388           aV1x = aV0x.Transformed( aTrsf );
5389           aPN1 = aPN0.Transformed( aTrsf );
5390
5391           // rotation 1 [ T1,T0 ]
5392           aAngleT1T0=-aDT1x.Angle( aDT0x );
5393           if (fabs(aAngleT1T0) > aTolAng) {
5394             aDT1T0=aDT1x^aDT0x;
5395             anAxT1T0.SetLocation( aV1x );
5396             anAxT1T0.SetDirection( aDT1T0 );
5397             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5398
5399             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5400           }
5401
5402           // rotation 2
5403           if ( theHasAngles ) {
5404             anAx1.SetLocation( aV1x );
5405             anAx1.SetDirection( aDT1x );
5406             aTrsfRot.SetRotation( anAx1, aAngle1x );
5407
5408             aPN1 = aPN1.Transformed( aTrsfRot );
5409           }
5410
5411           // make new node
5412           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5413           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5414             // create additional node
5415             double x = ( aPN1.X() + aPN0.X() )/2.;
5416             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5417             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5418             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5419             myLastCreatedNodes.Append(newNode);
5420             srcNodes.Append( node );
5421             listNewNodes.push_back( newNode );
5422           }
5423           aX = aPN1.X();
5424           aY = aPN1.Y();
5425           aZ = aPN1.Z();
5426           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5427           myLastCreatedNodes.Append(newNode);
5428           srcNodes.Append( node );
5429           listNewNodes.push_back( newNode );
5430
5431           aPN0 = aPN1;
5432           aP0x = aP1x;
5433           aV0x = aV1x;
5434           aDT0x = aDT1x;
5435         }
5436       }
5437
5438       else {
5439         // if current elem is quadratic and current node is not medium
5440         // we have to check - may be it is needed to insert additional nodes
5441         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5442           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5443           if(listNewNodes.size()==aNbTP-1) {
5444             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5445             gp_XYZ P(node->X(), node->Y(), node->Z());
5446             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5447             int i;
5448             for(i=0; i<aNbTP-1; i++) {
5449               const SMDS_MeshNode* N = *it;
5450               double x = ( N->X() + P.X() )/2.;
5451               double y = ( N->Y() + P.Y() )/2.;
5452               double z = ( N->Z() + P.Z() )/2.;
5453               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5454               srcNodes.Append( node );
5455               myLastCreatedNodes.Append(newN);
5456               aNodes[2*i] = newN;
5457               aNodes[2*i+1] = N;
5458               P = gp_XYZ(N->X(),N->Y(),N->Z());
5459             }
5460             listNewNodes.clear();
5461             for(i=0; i<2*(aNbTP-1); i++) {
5462               listNewNodes.push_back(aNodes[i]);
5463             }
5464           }
5465         }
5466       }
5467
5468       newNodesItVec.push_back( nIt );
5469     }
5470     // make new elements
5471     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5472     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5473     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5474   }
5475
5476   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5477
5478   if ( theMakeGroups )
5479     generateGroups( srcNodes, srcElems, "extruded");
5480
5481   return EXTR_OK;
5482 }
5483
5484
5485 //=======================================================================
5486 //function : LinearAngleVariation
5487 //purpose  : auxilary for ExtrusionAlongTrack
5488 //=======================================================================
5489 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5490                                             list<double>& Angles)
5491 {
5492   int nbAngles = Angles.size();
5493   if( nbSteps > nbAngles ) {
5494     vector<double> theAngles(nbAngles);
5495     list<double>::iterator it = Angles.begin();
5496     int i = -1;
5497     for(; it!=Angles.end(); it++) {
5498       i++;
5499       theAngles[i] = (*it);
5500     }
5501     list<double> res;
5502     double rAn2St = double( nbAngles ) / double( nbSteps );
5503     double angPrev = 0, angle;
5504     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5505       double angCur = rAn2St * ( iSt+1 );
5506       double angCurFloor  = floor( angCur );
5507       double angPrevFloor = floor( angPrev );
5508       if ( angPrevFloor == angCurFloor )
5509         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5510       else {
5511         int iP = int( angPrevFloor );
5512         double angPrevCeil = ceil(angPrev);
5513         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5514
5515         int iC = int( angCurFloor );
5516         if ( iC < nbAngles )
5517           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5518
5519         iP = int( angPrevCeil );
5520         while ( iC-- > iP )
5521           angle += theAngles[ iC ];
5522       }
5523       res.push_back(angle);
5524       angPrev = angCur;
5525     }
5526     Angles.clear();
5527     it = res.begin();
5528     for(; it!=res.end(); it++)
5529       Angles.push_back( *it );
5530   }
5531 }
5532
5533
5534 //================================================================================
5535 /*!
5536  * \brief Move or copy theElements applying theTrsf to their nodes
5537  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5538  *  \param theTrsf - transformation to apply
5539  *  \param theCopy - if true, create translated copies of theElems
5540  *  \param theMakeGroups - if true and theCopy, create translated groups
5541  *  \param theTargetMesh - mesh to copy translated elements into
5542  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5543  */
5544 //================================================================================
5545
5546 SMESH_MeshEditor::PGroupIDs
5547 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5548                              const gp_Trsf&     theTrsf,
5549                              const bool         theCopy,
5550                              const bool         theMakeGroups,
5551                              SMESH_Mesh*        theTargetMesh)
5552 {
5553   myLastCreatedElems.Clear();
5554   myLastCreatedNodes.Clear();
5555
5556   bool needReverse = false;
5557   string groupPostfix;
5558   switch ( theTrsf.Form() ) {
5559   case gp_PntMirror:
5560     MESSAGE("gp_PntMirror");
5561     needReverse = true;
5562     groupPostfix = "mirrored";
5563     break;
5564   case gp_Ax1Mirror:
5565     MESSAGE("gp_Ax1Mirror");
5566     groupPostfix = "mirrored";
5567     break;
5568   case gp_Ax2Mirror:
5569     MESSAGE("gp_Ax2Mirror");
5570     needReverse = true;
5571     groupPostfix = "mirrored";
5572     break;
5573   case gp_Rotation:
5574     MESSAGE("gp_Rotation");
5575     groupPostfix = "rotated";
5576     break;
5577   case gp_Translation:
5578     MESSAGE("gp_Translation");
5579     groupPostfix = "translated";
5580     break;
5581   case gp_Scale:
5582     MESSAGE("gp_Scale");
5583     groupPostfix = "scaled";
5584     break;
5585   case gp_CompoundTrsf: // different scale by axis
5586     MESSAGE("gp_CompoundTrsf");
5587     groupPostfix = "scaled";
5588     break;
5589   default:
5590     MESSAGE("default");
5591     needReverse = false;
5592     groupPostfix = "transformed";
5593   }
5594
5595   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5596   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5597   SMESHDS_Mesh* aMesh    = GetMeshDS();
5598
5599
5600   // map old node to new one
5601   TNodeNodeMap nodeMap;
5602
5603   // elements sharing moved nodes; those of them which have all
5604   // nodes mirrored but are not in theElems are to be reversed
5605   TIDSortedElemSet inverseElemSet;
5606
5607   // source elements for each generated one
5608   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5609
5610   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5611   TIDSortedElemSet orphanNode;
5612
5613   if ( theElems.empty() ) // transform the whole mesh
5614   {
5615     // add all elements
5616     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5617     while ( eIt->more() ) theElems.insert( eIt->next() );
5618     // add orphan nodes
5619     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5620     while ( nIt->more() )
5621     {
5622       const SMDS_MeshNode* node = nIt->next();
5623       if ( node->NbInverseElements() == 0)
5624         orphanNode.insert( node );
5625     }
5626   }
5627
5628   // loop on elements to transform nodes : first orphan nodes then elems
5629   TIDSortedElemSet::iterator itElem;
5630   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5631   for (int i=0; i<2; i++)
5632   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5633     const SMDS_MeshElement* elem = *itElem;
5634     if ( !elem )
5635       continue;
5636
5637     // loop on elem nodes
5638     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5639     while ( itN->more() ) {
5640
5641       const SMDS_MeshNode* node = cast2Node( itN->next() );
5642       // check if a node has been already transformed
5643       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5644         nodeMap.insert( make_pair ( node, node ));
5645       if ( !n2n_isnew.second )
5646         continue;
5647
5648       double coord[3];
5649       coord[0] = node->X();
5650       coord[1] = node->Y();
5651       coord[2] = node->Z();
5652       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5653       if ( theTargetMesh ) {
5654         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5655         n2n_isnew.first->second = newNode;
5656         myLastCreatedNodes.Append(newNode);
5657         srcNodes.Append( node );
5658       }
5659       else if ( theCopy ) {
5660         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5661         n2n_isnew.first->second = newNode;
5662         myLastCreatedNodes.Append(newNode);
5663         srcNodes.Append( node );
5664       }
5665       else {
5666         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5667         // node position on shape becomes invalid
5668         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5669           ( SMDS_SpacePosition::originSpacePosition() );
5670       }
5671
5672       // keep inverse elements
5673       if ( !theCopy && !theTargetMesh && needReverse ) {
5674         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5675         while ( invElemIt->more() ) {
5676           const SMDS_MeshElement* iel = invElemIt->next();
5677           inverseElemSet.insert( iel );
5678         }
5679       }
5680     }
5681   }
5682
5683   // either create new elements or reverse mirrored ones
5684   if ( !theCopy && !needReverse && !theTargetMesh )
5685     return PGroupIDs();
5686
5687   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5688   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5689     theElems.insert( *invElemIt );
5690
5691   // Replicate or reverse elements
5692
5693   std::vector<int> iForw;
5694   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5695   {
5696     const SMDS_MeshElement* elem = *itElem;
5697     if ( !elem || elem->GetType() == SMDSAbs_Node )
5698       continue;
5699
5700     int nbNodes = elem->NbNodes();
5701     int elemType = elem->GetType();
5702
5703     if (elem->IsPoly()) {
5704
5705       // polygon or polyhedral volume
5706       switch ( elemType ) {
5707       case SMDSAbs_Face:
5708         {
5709           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5710           int iNode = 0;
5711           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5712           while (itN->more()) {
5713             const SMDS_MeshNode* node =
5714               static_cast<const SMDS_MeshNode*>(itN->next());
5715             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5716             if (nodeMapIt == nodeMap.end())
5717               break; // not all nodes transformed
5718             if (needReverse) {
5719               // reverse mirrored faces and volumes
5720               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5721             } else {
5722               poly_nodes[iNode] = (*nodeMapIt).second;
5723             }
5724             iNode++;
5725           }
5726           if ( iNode != nbNodes )
5727             continue; // not all nodes transformed
5728
5729           if ( theTargetMesh ) {
5730             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5731             srcElems.Append( elem );
5732           }
5733           else if ( theCopy ) {
5734             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5735             srcElems.Append( elem );
5736           }
5737           else {
5738             aMesh->ChangePolygonNodes(elem, poly_nodes);
5739           }
5740         }
5741         break;
5742       case SMDSAbs_Volume:
5743         {
5744           const SMDS_VtkVolume* aPolyedre =
5745             dynamic_cast<const SMDS_VtkVolume*>( elem );
5746           if (!aPolyedre) {
5747             MESSAGE("Warning: bad volumic element");
5748             continue;
5749           }
5750
5751           vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
5752           vector<int> quantities;
5753
5754           bool allTransformed = true;
5755           int nbFaces = aPolyedre->NbFaces();
5756           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5757             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5758             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5759               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5760               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5761               if (nodeMapIt == nodeMap.end()) {
5762                 allTransformed = false; // not all nodes transformed
5763               } else {
5764                 poly_nodes.push_back((*nodeMapIt).second);
5765               }
5766               if ( needReverse && allTransformed )
5767                 std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
5768             }
5769             quantities.push_back(nbFaceNodes);
5770           }
5771           if ( !allTransformed )
5772             continue; // not all nodes transformed
5773
5774           if ( theTargetMesh ) {
5775             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5776             srcElems.Append( elem );
5777           }
5778           else if ( theCopy ) {
5779             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5780             srcElems.Append( elem );
5781           }
5782           else {
5783             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5784           }
5785         }
5786         break;
5787       default:;
5788       }
5789       continue;
5790
5791     } // elem->isPoly()
5792
5793     // Regular elements
5794
5795     while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
5796     const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
5797     const std::vector<int>& i = needReverse ? iRev : iForw;
5798
5799     // find transformed nodes
5800     vector<const SMDS_MeshNode*> nodes(nbNodes);
5801     int iNode = 0;
5802     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5803     while ( itN->more() ) {
5804       const SMDS_MeshNode* node =
5805         static_cast<const SMDS_MeshNode*>( itN->next() );
5806       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5807       if ( nodeMapIt == nodeMap.end() )
5808         break; // not all nodes transformed
5809       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5810     }
5811     if ( iNode != nbNodes )
5812       continue; // not all nodes transformed
5813
5814     if ( theTargetMesh ) {
5815       if ( SMDS_MeshElement* copy =
5816            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5817         myLastCreatedElems.Append( copy );
5818         srcElems.Append( elem );
5819       }
5820     }
5821     else if ( theCopy ) {
5822       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5823         srcElems.Append( elem );
5824     }
5825     else {
5826       // reverse element as it was reversed by transformation
5827       if ( nbNodes > 2 )
5828         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5829     }
5830
5831   } // loop on elements
5832
5833   PGroupIDs newGroupIDs;
5834
5835   if ( ( theMakeGroups && theCopy ) ||
5836        ( theMakeGroups && theTargetMesh ) )
5837     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5838
5839   return newGroupIDs;
5840 }
5841
5842 //=======================================================================
5843 /*!
5844  * \brief Create groups of elements made during transformation
5845  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5846  * \param elemGens - elements making corresponding myLastCreatedElems
5847  * \param postfix - to append to names of new groups
5848  */
5849 //=======================================================================
5850
5851 SMESH_MeshEditor::PGroupIDs
5852 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5853                                  const SMESH_SequenceOfElemPtr& elemGens,
5854                                  const std::string&             postfix,
5855                                  SMESH_Mesh*                    targetMesh)
5856 {
5857   PGroupIDs newGroupIDs( new list<int> );
5858   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5859
5860   // Sort existing groups by types and collect their names
5861
5862   // to store an old group and a generated new one
5863   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5864   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5865   // group names
5866   set< string > groupNames;
5867   //
5868   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5869   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5870   while ( groupIt->more() ) {
5871     SMESH_Group * group = groupIt->next();
5872     if ( !group ) continue;
5873     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5874     if ( !groupDS || groupDS->IsEmpty() ) continue;
5875     groupNames.insert( group->GetName() );
5876     groupDS->SetStoreName( group->GetName() );
5877     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5878   }
5879
5880   // Groups creation
5881
5882   // loop on nodes and elements
5883   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5884   {
5885     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5886     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5887     if ( gens.Length() != elems.Length() )
5888       throw SALOME_Exception(LOCALIZED("invalid args"));
5889
5890     // loop on created elements
5891     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5892     {
5893       const SMDS_MeshElement* sourceElem = gens( iElem );
5894       if ( !sourceElem ) {
5895         MESSAGE("generateGroups(): NULL source element");
5896         continue;
5897       }
5898       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5899       if ( groupsOldNew.empty() ) {
5900         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5901           ++iElem; // skip all elements made by sourceElem
5902         continue;
5903       }
5904       // collect all elements made by sourceElem
5905       list< const SMDS_MeshElement* > resultElems;
5906       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5907         if ( resElem != sourceElem )
5908           resultElems.push_back( resElem );
5909       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5910         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5911           if ( resElem != sourceElem )
5912             resultElems.push_back( resElem );
5913       // do not generate element groups from node ones
5914 //      if ( sourceElem->GetType() == SMDSAbs_Node &&
5915 //           elems( iElem )->GetType() != SMDSAbs_Node )
5916 //        continue;
5917
5918       // add resultElems to groups made by ones the sourceElem belongs to
5919       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5920       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5921       {
5922         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5923         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5924         {
5925           SMDS_MeshGroup* & newGroup = gOldNew->second;
5926           if ( !newGroup )// create a new group
5927           {
5928             // make a name
5929             string name = oldGroup->GetStoreName();
5930             if ( !targetMesh ) {
5931               name += "_";
5932               name += postfix;
5933               int nb = 0;
5934               while ( !groupNames.insert( name ).second ) // name exists
5935               {
5936                 if ( nb == 0 ) {
5937                   name += "_1";
5938                 }
5939                 else {
5940                   TCollection_AsciiString nbStr(nb+1);
5941                   name.resize( name.rfind('_')+1 );
5942                   name += nbStr.ToCString();
5943                 }
5944                 ++nb;
5945               }
5946             }
5947             // make a group
5948             int id;
5949             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5950                                                  name.c_str(), id );
5951             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5952             newGroup = & groupDS->SMDSGroup();
5953             newGroupIDs->push_back( id );
5954           }
5955
5956           // fill in a new group
5957           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5958           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5959             newGroup->Add( *resElemIt );
5960         }
5961       }
5962     } // loop on created elements
5963   }// loop on nodes and elements
5964
5965   return newGroupIDs;
5966 }
5967
5968 //================================================================================
5969 /*!
5970  * \brief Return list of group of nodes close to each other within theTolerance
5971  *        Search among theNodes or in the whole mesh if theNodes is empty using
5972  *        an Octree algorithm
5973  */
5974 //================================================================================
5975
5976 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
5977                                             const double         theTolerance,
5978                                             TListOfListOfNodes & theGroupsOfNodes)
5979 {
5980   myLastCreatedElems.Clear();
5981   myLastCreatedNodes.Clear();
5982
5983   if ( theNodes.empty() )
5984   { // get all nodes in the mesh
5985     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
5986     while ( nIt->more() )
5987       theNodes.insert( theNodes.end(),nIt->next());
5988   }
5989
5990   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
5991 }
5992
5993
5994 //=======================================================================
5995 /*!
5996  * \brief Implementation of search for the node closest to point
5997  */
5998 //=======================================================================
5999
6000 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6001 {
6002   //---------------------------------------------------------------------
6003   /*!
6004    * \brief Constructor
6005    */
6006   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6007   {
6008     myMesh = ( SMESHDS_Mesh* ) theMesh;
6009
6010     TIDSortedNodeSet nodes;
6011     if ( theMesh ) {
6012       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6013       while ( nIt->more() )
6014         nodes.insert( nodes.end(), nIt->next() );
6015     }
6016     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6017
6018     // get max size of a leaf box
6019     SMESH_OctreeNode* tree = myOctreeNode;
6020     while ( !tree->isLeaf() )
6021     {
6022       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6023       if ( cIt->more() )
6024         tree = cIt->next();
6025     }
6026     myHalfLeafSize = tree->maxSize() / 2.;
6027   }
6028
6029   //---------------------------------------------------------------------
6030   /*!
6031    * \brief Move node and update myOctreeNode accordingly
6032    */
6033   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6034   {
6035     myOctreeNode->UpdateByMoveNode( node, toPnt );
6036     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6037   }
6038
6039   //---------------------------------------------------------------------
6040   /*!
6041    * \brief Do it's job
6042    */
6043   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6044   {
6045     map<double, const SMDS_MeshNode*> dist2Nodes;
6046     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6047     if ( !dist2Nodes.empty() )
6048       return dist2Nodes.begin()->second;
6049     list<const SMDS_MeshNode*> nodes;
6050     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6051
6052     double minSqDist = DBL_MAX;
6053     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6054     {
6055       // sort leafs by their distance from thePnt
6056       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6057       TDistTreeMap treeMap;
6058       list< SMESH_OctreeNode* > treeList;
6059       list< SMESH_OctreeNode* >::iterator trIt;
6060       treeList.push_back( myOctreeNode );
6061
6062       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6063       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6064       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6065       {
6066         SMESH_OctreeNode* tree = *trIt;
6067         if ( !tree->isLeaf() ) // put children to the queue
6068         {
6069           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6070           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6071           while ( cIt->more() )
6072             treeList.push_back( cIt->next() );
6073         }
6074         else if ( tree->NbNodes() ) // put a tree to the treeMap
6075         {
6076           const Bnd_B3d& box = tree->getBox();
6077           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6078           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6079           if ( !it_in.second ) // not unique distance to box center
6080             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6081         }
6082       }
6083       // find distance after which there is no sense to check tree's
6084       double sqLimit = DBL_MAX;
6085       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6086       if ( treeMap.size() > 5 ) {
6087         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6088         const Bnd_B3d& box = closestTree->getBox();
6089         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6090         sqLimit = limit * limit;
6091       }
6092       // get all nodes from trees
6093       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6094         if ( sqDist_tree->first > sqLimit )
6095           break;
6096         SMESH_OctreeNode* tree = sqDist_tree->second;
6097         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6098       }
6099     }
6100     // find closest among nodes
6101     minSqDist = DBL_MAX;
6102     const SMDS_MeshNode* closestNode = 0;
6103     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6104     for ( ; nIt != nodes.end(); ++nIt ) {
6105       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6106       if ( minSqDist > sqDist ) {
6107         closestNode = *nIt;
6108         minSqDist = sqDist;
6109       }
6110     }
6111     return closestNode;
6112   }
6113
6114   //---------------------------------------------------------------------
6115   /*!
6116    * \brief Destructor
6117    */
6118   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6119
6120   //---------------------------------------------------------------------
6121   /*!
6122    * \brief Return the node tree
6123    */
6124   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6125
6126 private:
6127   SMESH_OctreeNode* myOctreeNode;
6128   SMESHDS_Mesh*     myMesh;
6129   double            myHalfLeafSize; // max size of a leaf box
6130 };
6131
6132 //=======================================================================
6133 /*!
6134  * \brief Return SMESH_NodeSearcher
6135  */
6136 //=======================================================================
6137
6138 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6139 {
6140   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6141 }
6142
6143 // ========================================================================
6144 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6145 {
6146   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6147   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6148   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6149
6150   //=======================================================================
6151   /*!
6152    * \brief Octal tree of bounding boxes of elements
6153    */
6154   //=======================================================================
6155
6156   class ElementBndBoxTree : public SMESH_Octree
6157   {
6158   public:
6159
6160     ElementBndBoxTree(const SMDS_Mesh&     mesh,
6161                       SMDSAbs_ElementType  elemType,
6162                       SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(),
6163                       double               tolerance = NodeRadius );
6164     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems );
6165     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6166     void getElementsInSphere ( const gp_XYZ& center,
6167                                const double  radius, TIDSortedElemSet& foundElems);
6168     size_t getSize() { return std::max( _size, _elements.size() ); }
6169     ~ElementBndBoxTree();
6170
6171   protected:
6172     ElementBndBoxTree():_size(0) {}
6173     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6174     void          buildChildrenData();
6175     Bnd_B3d*      buildRootBox();
6176   private:
6177     //!< Bounding box of element
6178     struct ElementBox : public Bnd_B3d
6179     {
6180       const SMDS_MeshElement* _element;
6181       int                     _refCount; // an ElementBox can be included in several tree branches
6182       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6183     };
6184     vector< ElementBox* > _elements;
6185     size_t                _size;
6186   };
6187
6188   //================================================================================
6189   /*!
6190    * \brief ElementBndBoxTree creation
6191    */
6192   //================================================================================
6193
6194   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6195     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6196   {
6197     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6198     _elements.reserve( nbElems );
6199
6200     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6201     while ( elemIt->more() )
6202       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6203
6204     compute();
6205   }
6206
6207   //================================================================================
6208   /*!
6209    * \brief Destructor
6210    */
6211   //================================================================================
6212
6213   ElementBndBoxTree::~ElementBndBoxTree()
6214   {
6215     for ( int i = 0; i < _elements.size(); ++i )
6216       if ( --_elements[i]->_refCount <= 0 )
6217         delete _elements[i];
6218   }
6219
6220   //================================================================================
6221   /*!
6222    * \brief Return the maximal box
6223    */
6224   //================================================================================
6225
6226   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6227   {
6228     Bnd_B3d* box = new Bnd_B3d;
6229     for ( int i = 0; i < _elements.size(); ++i )
6230       box->Add( *_elements[i] );
6231     return box;
6232   }
6233
6234   //================================================================================
6235   /*!
6236    * \brief Redistrubute element boxes among children
6237    */
6238   //================================================================================
6239
6240   void ElementBndBoxTree::buildChildrenData()
6241   {
6242     for ( int i = 0; i < _elements.size(); ++i )
6243     {
6244       for (int j = 0; j < 8; j++)
6245       {
6246         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6247         {
6248           _elements[i]->_refCount++;
6249           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6250         }
6251       }
6252       _elements[i]->_refCount--;
6253     }
6254     _size = _elements.size();
6255     SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory
6256
6257     for (int j = 0; j < 8; j++)
6258     {
6259       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6260       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6261         child->myIsLeaf = true;
6262
6263       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6264         SMESHUtils::CompactVector( child->_elements );
6265     }
6266   }
6267
6268   //================================================================================
6269   /*!
6270    * \brief Return elements which can include the point
6271    */
6272   //================================================================================
6273
6274   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6275                                                 TIDSortedElemSet& foundElems)
6276   {
6277     if ( getBox().IsOut( point.XYZ() ))
6278       return;
6279
6280     if ( isLeaf() )
6281     {
6282       for ( int i = 0; i < _elements.size(); ++i )
6283         if ( !_elements[i]->IsOut( point.XYZ() ))
6284           foundElems.insert( _elements[i]->_element );
6285     }
6286     else
6287     {
6288       for (int i = 0; i < 8; i++)
6289         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6290     }
6291   }
6292
6293   //================================================================================
6294   /*!
6295    * \brief Return elements which can be intersected by the line
6296    */
6297   //================================================================================
6298
6299   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6300                                                TIDSortedElemSet& foundElems)
6301   {
6302     if ( getBox().IsOut( line ))
6303       return;
6304
6305     if ( isLeaf() )
6306     {
6307       for ( int i = 0; i < _elements.size(); ++i )
6308         if ( !_elements[i]->IsOut( line ))
6309           foundElems.insert( _elements[i]->_element );
6310     }
6311     else
6312     {
6313       for (int i = 0; i < 8; i++)
6314         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6315     }
6316   }
6317
6318   //================================================================================
6319   /*!
6320    * \brief Return elements from leaves intersecting the sphere
6321    */
6322   //================================================================================
6323
6324   void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ&     center,
6325                                                 const double      radius,
6326                                                 TIDSortedElemSet& foundElems)
6327   {
6328     if ( getBox().IsOut( center, radius ))
6329       return;
6330
6331     if ( isLeaf() )
6332     {
6333       for ( int i = 0; i < _elements.size(); ++i )
6334         if ( !_elements[i]->IsOut( center, radius ))
6335           foundElems.insert( _elements[i]->_element );
6336     }
6337     else
6338     {
6339       for (int i = 0; i < 8; i++)
6340         ((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems );
6341     }
6342   }
6343
6344   //================================================================================
6345   /*!
6346    * \brief Construct the element box
6347    */
6348   //================================================================================
6349
6350   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6351   {
6352     _element  = elem;
6353     _refCount = 1;
6354     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6355     while ( nIt->more() )
6356       Add( SMESH_TNodeXYZ( nIt->next() ));
6357     Enlarge( tolerance );
6358   }
6359
6360 } // namespace
6361
6362 //=======================================================================
6363 /*!
6364  * \brief Implementation of search for the elements by point and
6365  *        of classification of point in 2D mesh
6366  */
6367 //=======================================================================
6368
6369 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6370 {
6371   SMESHDS_Mesh*                _mesh;
6372   SMDS_ElemIteratorPtr         _meshPartIt;
6373   ElementBndBoxTree*           _ebbTree;
6374   SMESH_NodeSearcherImpl*      _nodeSearcher;
6375   SMDSAbs_ElementType          _elementType;
6376   double                       _tolerance;
6377   bool                         _outerFacesFound;
6378   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6379
6380   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6381     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6382   ~SMESH_ElementSearcherImpl()
6383   {
6384     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6385     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6386   }
6387   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6388                                   SMDSAbs_ElementType                type,
6389                                   vector< const SMDS_MeshElement* >& foundElements);
6390   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6391   virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt&       point,
6392                                                  SMDSAbs_ElementType type );
6393
6394   void GetElementsNearLine( const gp_Ax1&                      line,
6395                             SMDSAbs_ElementType                type,
6396                             vector< const SMDS_MeshElement* >& foundElems);
6397   double getTolerance();
6398   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6399                             const double tolerance, double & param);
6400   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6401   bool isOuterBoundary(const SMDS_MeshElement* face) const
6402   {
6403     return _outerFaces.empty() || _outerFaces.count(face);
6404   }
6405   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6406   {
6407     const SMDS_MeshElement* _face;
6408     gp_Vec                  _faceNorm;
6409     bool                    _coincides; //!< the line lays in face plane
6410     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6411       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6412   };
6413   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6414   {
6415     SMESH_TLink      _link;
6416     TIDSortedElemSet _faces;
6417     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6418       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6419   };
6420 };
6421
6422 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6423 {
6424   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6425              << ", _coincides="<<i._coincides << ")";
6426 }
6427
6428 //=======================================================================
6429 /*!
6430  * \brief define tolerance for search
6431  */
6432 //=======================================================================
6433
6434 double SMESH_ElementSearcherImpl::getTolerance()
6435 {
6436   if ( _tolerance < 0 )
6437   {
6438     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6439
6440     _tolerance = 0;
6441     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6442     {
6443       double boxSize = _nodeSearcher->getTree()->maxSize();
6444       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6445     }
6446     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6447     {
6448       double boxSize = _ebbTree->maxSize();
6449       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6450     }
6451     if ( _tolerance == 0 )
6452     {
6453       // define tolerance by size of a most complex element
6454       int complexType = SMDSAbs_Volume;
6455       while ( complexType > SMDSAbs_All &&
6456               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6457         --complexType;
6458       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6459       double elemSize;
6460       if ( complexType == int( SMDSAbs_Node ))
6461       {
6462         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6463         elemSize = 1;
6464         if ( meshInfo.NbNodes() > 2 )
6465           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6466       }
6467       else
6468       {
6469         SMDS_ElemIteratorPtr elemIt =
6470             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6471         const SMDS_MeshElement* elem = elemIt->next();
6472         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6473         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6474         elemSize = 0;
6475         while ( nodeIt->more() )
6476         {
6477           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6478           elemSize = max( dist, elemSize );
6479         }
6480       }
6481       _tolerance = 1e-4 * elemSize;
6482     }
6483   }
6484   return _tolerance;
6485 }
6486
6487 //================================================================================
6488 /*!
6489  * \brief Find intersection of the line and an edge of face and return parameter on line
6490  */
6491 //================================================================================
6492
6493 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6494                                                      const SMDS_MeshElement* face,
6495                                                      const double            tol,
6496                                                      double &                param)
6497 {
6498   int nbInts = 0;
6499   param = 0;
6500
6501   GeomAPI_ExtremaCurveCurve anExtCC;
6502   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6503   
6504   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6505   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6506   {
6507     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6508                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6509     anExtCC.Init( lineCurve, edge);
6510     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6511     {
6512       Quantity_Parameter pl, pe;
6513       anExtCC.LowerDistanceParameters( pl, pe );
6514       param += pl;
6515       if ( ++nbInts == 2 )
6516         break;
6517     }
6518   }
6519   if ( nbInts > 0 ) param /= nbInts;
6520   return nbInts > 0;
6521 }
6522 //================================================================================
6523 /*!
6524  * \brief Find all faces belonging to the outer boundary of mesh
6525  */
6526 //================================================================================
6527
6528 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6529 {
6530   if ( _outerFacesFound ) return;
6531
6532   // Collect all outer faces by passing from one outer face to another via their links
6533   // and BTW find out if there are internal faces at all.
6534
6535   // checked links and links where outer boundary meets internal one
6536   set< SMESH_TLink > visitedLinks, seamLinks;
6537
6538   // links to treat with already visited faces sharing them
6539   list < TFaceLink > startLinks;
6540
6541   // load startLinks with the first outerFace
6542   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6543   _outerFaces.insert( outerFace );
6544
6545   TIDSortedElemSet emptySet;
6546   while ( !startLinks.empty() )
6547   {
6548     const SMESH_TLink& link  = startLinks.front()._link;
6549     TIDSortedElemSet&  faces = startLinks.front()._faces;
6550
6551     outerFace = *faces.begin();
6552     // find other faces sharing the link
6553     const SMDS_MeshElement* f;
6554     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6555       faces.insert( f );
6556
6557     // select another outer face among the found 
6558     const SMDS_MeshElement* outerFace2 = 0;
6559     if ( faces.size() == 2 )
6560     {
6561       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6562     }
6563     else if ( faces.size() > 2 )
6564     {
6565       seamLinks.insert( link );
6566
6567       // link direction within the outerFace
6568       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6569                    SMESH_TNodeXYZ( link.node2()));
6570       int i1 = outerFace->GetNodeIndex( link.node1() );
6571       int i2 = outerFace->GetNodeIndex( link.node2() );
6572       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6573       if ( rev ) n1n2.Reverse();
6574       // outerFace normal
6575       gp_XYZ ofNorm, fNorm;
6576       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6577       {
6578         // direction from the link inside outerFace
6579         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6580         // sort all other faces by angle with the dirInOF
6581         map< double, const SMDS_MeshElement* > angle2Face;
6582         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6583         for ( ; face != faces.end(); ++face )
6584         {
6585           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6586             continue;
6587           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6588           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6589           if ( angle < 0 ) angle += 2. * M_PI;
6590           angle2Face.insert( make_pair( angle, *face ));
6591         }
6592         if ( !angle2Face.empty() )
6593           outerFace2 = angle2Face.begin()->second;
6594       }
6595     }
6596     // store the found outer face and add its links to continue seaching from
6597     if ( outerFace2 )
6598     {
6599       _outerFaces.insert( outerFace );
6600       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6601       for ( int i = 0; i < nbNodes; ++i )
6602       {
6603         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6604         if ( visitedLinks.insert( link2 ).second )
6605           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6606       }
6607     }
6608     startLinks.pop_front();
6609   }
6610   _outerFacesFound = true;
6611
6612   if ( !seamLinks.empty() )
6613   {
6614     // There are internal boundaries touching the outher one,
6615     // find all faces of internal boundaries in order to find
6616     // faces of boundaries of holes, if any.
6617     
6618   }
6619   else
6620   {
6621     _outerFaces.clear();
6622   }
6623 }
6624
6625 //=======================================================================
6626 /*!
6627  * \brief Find elements of given type where the given point is IN or ON.
6628  *        Returns nb of found elements and elements them-selves.
6629  *
6630  * 'ALL' type means elements of any type excluding nodes and 0D elements
6631  */
6632 //=======================================================================
6633
6634 int SMESH_ElementSearcherImpl::
6635 FindElementsByPoint(const gp_Pnt&                      point,
6636                     SMDSAbs_ElementType                type,
6637                     vector< const SMDS_MeshElement* >& foundElements)
6638 {
6639   foundElements.clear();
6640
6641   double tolerance = getTolerance();
6642
6643   // =================================================================================
6644   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6645   {
6646     if ( !_nodeSearcher )
6647       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6648
6649     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6650     if ( !closeNode ) return foundElements.size();
6651
6652     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6653       return foundElements.size(); // to far from any node
6654
6655     if ( type == SMDSAbs_Node )
6656     {
6657       foundElements.push_back( closeNode );
6658     }
6659     else
6660     {
6661       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6662       while ( elemIt->more() )
6663         foundElements.push_back( elemIt->next() );
6664     }
6665   }
6666   // =================================================================================
6667   else // elements more complex than 0D
6668   {
6669     if ( !_ebbTree || _elementType != type )
6670     {
6671       if ( _ebbTree ) delete _ebbTree;
6672       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6673     }
6674     TIDSortedElemSet suspectElems;
6675     _ebbTree->getElementsNearPoint( point, suspectElems );
6676     TIDSortedElemSet::iterator elem = suspectElems.begin();
6677     for ( ; elem != suspectElems.end(); ++elem )
6678       if ( !SMESH_MeshEditor::IsOut( *elem, point, tolerance ))
6679         foundElements.push_back( *elem );
6680   }
6681   return foundElements.size();
6682 }
6683
6684 //=======================================================================
6685 /*!
6686  * \brief Find an element of given type most close to the given point
6687  *
6688  * WARNING: Only face search is implemeneted so far
6689  */
6690 //=======================================================================
6691
6692 const SMDS_MeshElement*
6693 SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt&       point,
6694                                           SMDSAbs_ElementType type )
6695 {
6696   const SMDS_MeshElement* closestElem = 0;
6697
6698   if ( type == SMDSAbs_Face )
6699   {
6700     if ( !_ebbTree || _elementType != type )
6701     {
6702       if ( _ebbTree ) delete _ebbTree;
6703       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
6704     }
6705     TIDSortedElemSet suspectElems;
6706     _ebbTree->getElementsNearPoint( point, suspectElems );
6707     
6708     if ( suspectElems.empty() && _ebbTree->maxSize() > 0 )
6709     {
6710       gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox().CornerMin() +
6711                                  _ebbTree->getBox().CornerMax() );
6712       double radius;
6713       if ( _ebbTree->getBox().IsOut( point.XYZ() ))
6714         radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize();
6715       else
6716         radius = _ebbTree->maxSize() / pow( 2., _ebbTree->getHeight()) / 2;
6717       while ( suspectElems.empty() )
6718       {
6719         _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
6720         radius *= 1.1;
6721       }
6722     }
6723     double minDist = std::numeric_limits<double>::max();
6724     multimap< double, const SMDS_MeshElement* > dist2face;
6725     TIDSortedElemSet::iterator elem = suspectElems.begin();
6726     for ( ; elem != suspectElems.end(); ++elem )
6727     {
6728       double dist = SMESH_MeshEditor::GetDistance( dynamic_cast<const SMDS_MeshFace*>(*elem),
6729                                                    point );
6730       if ( dist < minDist + 1e-10)
6731       {
6732         minDist = dist;
6733         dist2face.insert( dist2face.begin(), make_pair( dist, *elem ));
6734       }
6735     }
6736     if ( !dist2face.empty() )
6737     {
6738       multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin();
6739       closestElem = d2f->second;
6740       // if there are several elements at the same distance, select one
6741       // with GC closest to the point
6742       typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
6743       double minDistToGC = 0;
6744       for ( ++d2f; d2f != dist2face.end() && fabs( d2f->first - minDist ) < 1e-10; ++d2f )
6745       {
6746         if ( minDistToGC == 0 )
6747         {
6748           gp_XYZ gc(0,0,0);
6749           gc = accumulate( TXyzIterator(closestElem->nodesIterator()),
6750                            TXyzIterator(), gc ) / closestElem->NbNodes();
6751           minDistToGC = point.SquareDistance( gc );
6752         }
6753         gp_XYZ gc(0,0,0);
6754         gc = accumulate( TXyzIterator( d2f->second->nodesIterator()),
6755                          TXyzIterator(), gc ) / d2f->second->NbNodes();
6756         double d = point.SquareDistance( gc );
6757         if ( d < minDistToGC )
6758         {
6759           minDistToGC = d;
6760           closestElem = d2f->second;
6761         }
6762       }
6763       // cout << "FindClosestTo( " <<point.X()<<", "<<point.Y()<<", "<<point.Z()<<" ) FACE "
6764       //      <<closestElem->GetID() << " DIST " << minDist << endl;
6765     }
6766   }
6767   else
6768   {
6769     // NOT IMPLEMENTED SO FAR
6770   }
6771   return closestElem;
6772 }
6773
6774
6775 //================================================================================
6776 /*!
6777  * \brief Classify the given point in the closed 2D mesh
6778  */
6779 //================================================================================
6780
6781 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6782 {
6783   double tolerance = getTolerance();
6784   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6785   {
6786     if ( _ebbTree ) delete _ebbTree;
6787     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6788   }
6789   // Algo: analyse transition of a line starting at the point through mesh boundary;
6790   // try three lines parallel to axis of the coordinate system and perform rough
6791   // analysis. If solution is not clear perform thorough analysis.
6792
6793   const int nbAxes = 3;
6794   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6795   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6796   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6797   multimap< int, int > nbInt2Axis; // to find the simplest case
6798   for ( int axis = 0; axis < nbAxes; ++axis )
6799   {
6800     gp_Ax1 lineAxis( point, axisDir[axis]);
6801     gp_Lin line    ( lineAxis );
6802
6803     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6804     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6805
6806     // Intersect faces with the line
6807
6808     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6809     TIDSortedElemSet::iterator face = suspectFaces.begin();
6810     for ( ; face != suspectFaces.end(); ++face )
6811     {
6812       // get face plane
6813       gp_XYZ fNorm;
6814       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6815       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6816
6817       // perform intersection
6818       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6819       if ( !intersection.IsDone() )
6820         continue;
6821       if ( intersection.IsInQuadric() )
6822       {
6823         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6824       }
6825       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6826       {
6827         gp_Pnt intersectionPoint = intersection.Point(1);
6828         if ( !SMESH_MeshEditor::IsOut( *face, intersectionPoint, tolerance ))
6829           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6830       }
6831     }
6832     // Analyse intersections roughly
6833
6834     int nbInter = u2inters.size();
6835     if ( nbInter == 0 )
6836       return TopAbs_OUT; 
6837
6838     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6839     if ( nbInter == 1 ) // not closed mesh
6840       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6841
6842     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6843       return TopAbs_ON;
6844
6845     if ( (f<0) == (l<0) )
6846       return TopAbs_OUT;
6847
6848     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6849     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6850     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6851       return TopAbs_IN;
6852
6853     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6854
6855     if ( _outerFacesFound ) break; // pass to thorough analysis
6856
6857   } // three attempts - loop on CS axes
6858
6859   // Analyse intersections thoroughly.
6860   // We make two loops maximum, on the first one we only exclude touching intersections,
6861   // on the second, if situation is still unclear, we gather and use information on
6862   // position of faces (internal or outer). If faces position is already gathered,
6863   // we make the second loop right away.
6864
6865   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6866   {
6867     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6868     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6869     {
6870       int axis = nb_axis->second;
6871       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6872
6873       gp_Ax1 lineAxis( point, axisDir[axis]);
6874       gp_Lin line    ( lineAxis );
6875
6876       // add tangent intersections to u2inters
6877       double param;
6878       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6879       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6880         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6881           u2inters.insert(make_pair( param, *tgtInt ));
6882       tangentInters[ axis ].clear();
6883
6884       // Count intersections before and after the point excluding touching ones.
6885       // If hasPositionInfo we count intersections of outer boundary only
6886
6887       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6888       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6889       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6890       bool ok = ! u_int1->second._coincides;
6891       while ( ok && u_int1 != u2inters.end() )
6892       {
6893         double u = u_int1->first;
6894         bool touchingInt = false;
6895         if ( ++u_int2 != u2inters.end() )
6896         {
6897           // skip intersections at the same point (if the line passes through edge or node)
6898           int nbSamePnt = 0;
6899           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6900           {
6901             ++nbSamePnt;
6902             ++u_int2;
6903           }
6904
6905           // skip tangent intersections
6906           int nbTgt = 0;
6907           const SMDS_MeshElement* prevFace = u_int1->second._face;
6908           while ( ok && u_int2->second._coincides )
6909           {
6910             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6911               ok = false;
6912             else
6913             {
6914               nbTgt++;
6915               u_int2++;
6916               ok = ( u_int2 != u2inters.end() );
6917             }
6918           }
6919           if ( !ok ) break;
6920
6921           // skip intersections at the same point after tangent intersections
6922           if ( nbTgt > 0 )
6923           {
6924             double u2 = u_int2->first;
6925             ++u_int2;
6926             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6927             {
6928               ++nbSamePnt;
6929               ++u_int2;
6930             }
6931           }
6932           // decide if we skipped a touching intersection
6933           if ( nbSamePnt + nbTgt > 0 )
6934           {
6935             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6936             map< double, TInters >::iterator u_int = u_int1;
6937             for ( ; u_int != u_int2; ++u_int )
6938             {
6939               if ( u_int->second._coincides ) continue;
6940               double dot = u_int->second._faceNorm * line.Direction();
6941               if ( dot > maxDot ) maxDot = dot;
6942               if ( dot < minDot ) minDot = dot;
6943             }
6944             touchingInt = ( minDot*maxDot < 0 );
6945           }
6946         }
6947         if ( !touchingInt )
6948         {
6949           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6950           {
6951             if ( u < 0 )
6952               ++nbIntBeforePoint;
6953             else
6954               ++nbIntAfterPoint;
6955           }
6956           if ( u < f ) f = u;
6957           if ( u > l ) l = u;
6958         }
6959
6960         u_int1 = u_int2; // to next intersection
6961
6962       } // loop on intersections with one line
6963
6964       if ( ok )
6965       {
6966         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6967           return TopAbs_ON;
6968
6969         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6970           return TopAbs_OUT; 
6971
6972         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6973           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6974
6975         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6976           return TopAbs_IN;
6977
6978         if ( (f<0) == (l<0) )
6979           return TopAbs_OUT;
6980
6981         if ( hasPositionInfo )
6982           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6983       }
6984     } // loop on intersections of the tree lines - thorough analysis
6985
6986     if ( !hasPositionInfo )
6987     {
6988       // gather info on faces position - is face in the outer boundary or not
6989       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6990       findOuterBoundary( u2inters.begin()->second._face );
6991     }
6992
6993   } // two attempts - with and w/o faces position info in the mesh
6994
6995   return TopAbs_UNKNOWN;
6996 }
6997
6998 //=======================================================================
6999 /*!
7000  * \brief Return elements possibly intersecting the line
7001  */
7002 //=======================================================================
7003
7004 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7005                                                      SMDSAbs_ElementType                type,
7006                                                      vector< const SMDS_MeshElement* >& foundElems)
7007 {
7008   if ( !_ebbTree || _elementType != type )
7009   {
7010     if ( _ebbTree ) delete _ebbTree;
7011     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7012   }
7013   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7014   _ebbTree->getElementsNearLine( line, suspectFaces );
7015   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7016 }
7017
7018 //=======================================================================
7019 /*!
7020  * \brief Return SMESH_ElementSearcher
7021  */
7022 //=======================================================================
7023
7024 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7025 {
7026   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7027 }
7028
7029 //=======================================================================
7030 /*!
7031  * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
7032  */
7033 //=======================================================================
7034
7035 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7036 {
7037   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7038 }
7039
7040 //=======================================================================
7041 /*!
7042  * \brief Return true if the point is IN or ON of the element
7043  */
7044 //=======================================================================
7045
7046 bool SMESH_MeshEditor::IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7047 {
7048   if ( element->GetType() == SMDSAbs_Volume)
7049   {
7050     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7051   }
7052
7053   // get ordered nodes
7054
7055   vector< gp_XYZ > xyz;
7056   vector<const SMDS_MeshNode*> nodeList;
7057
7058   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7059   if ( element->IsQuadratic() ) {
7060     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7061       nodeIt = f->interlacedNodesElemIterator();
7062     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7063       nodeIt = e->interlacedNodesElemIterator();
7064   }
7065   while ( nodeIt->more() )
7066     {
7067       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7068       xyz.push_back( SMESH_TNodeXYZ(node) );
7069       nodeList.push_back(node);
7070     }
7071
7072   int i, nbNodes = element->NbNodes();
7073
7074   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7075   {
7076     // compute face normal
7077     gp_Vec faceNorm(0,0,0);
7078     xyz.push_back( xyz.front() );
7079     nodeList.push_back( nodeList.front() );
7080     for ( i = 0; i < nbNodes; ++i )
7081     {
7082       gp_Vec edge1( xyz[i+1], xyz[i]);
7083       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7084       faceNorm += edge1 ^ edge2;
7085     }
7086     double normSize = faceNorm.Magnitude();
7087     if ( normSize <= tol )
7088     {
7089       // degenerated face: point is out if it is out of all face edges
7090       for ( i = 0; i < nbNodes; ++i )
7091       {
7092         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7093         if ( !IsOut( &edge, point, tol ))
7094           return false;
7095       }
7096       return true;
7097     }
7098     faceNorm /= normSize;
7099
7100     // check if the point lays on face plane
7101     gp_Vec n2p( xyz[0], point );
7102     if ( fabs( n2p * faceNorm ) > tol )
7103       return true; // not on face plane
7104
7105     // check if point is out of face boundary:
7106     // define it by closest transition of a ray point->infinity through face boundary
7107     // on the face plane.
7108     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7109     // to find intersections of the ray with the boundary.
7110     gp_Vec ray = n2p;
7111     gp_Vec plnNorm = ray ^ faceNorm;
7112     normSize = plnNorm.Magnitude();
7113     if ( normSize <= tol ) return false; // point coincides with the first node
7114     plnNorm /= normSize;
7115     // for each node of the face, compute its signed distance to the plane
7116     vector<double> dist( nbNodes + 1);
7117     for ( i = 0; i < nbNodes; ++i )
7118     {
7119       gp_Vec n2p( xyz[i], point );
7120       dist[i] = n2p * plnNorm;
7121     }
7122     dist.back() = dist.front();
7123     // find the closest intersection
7124     int    iClosest = -1;
7125     double rClosest, distClosest = 1e100;;
7126     gp_Pnt pClosest;
7127     for ( i = 0; i < nbNodes; ++i )
7128     {
7129       double r;
7130       if ( fabs( dist[i]) < tol )
7131         r = 0.;
7132       else if ( fabs( dist[i+1]) < tol )
7133         r = 1.;
7134       else if ( dist[i] * dist[i+1] < 0 )
7135         r = dist[i] / ( dist[i] - dist[i+1] );
7136       else
7137         continue; // no intersection
7138       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7139       gp_Vec p2int ( point, pInt);
7140       if ( p2int * ray > -tol ) // right half-space
7141       {
7142         double intDist = p2int.SquareMagnitude();
7143         if ( intDist < distClosest )
7144         {
7145           iClosest = i;
7146           rClosest = r;
7147           pClosest = pInt;
7148           distClosest = intDist;
7149         }
7150       }
7151     }
7152     if ( iClosest < 0 )
7153       return true; // no intesections - out
7154
7155     // analyse transition
7156     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7157     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7158     gp_Vec p2int ( point, pClosest );
7159     bool out = (edgeNorm * p2int) < -tol;
7160     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7161       return out;
7162
7163     // ray pass through a face node; analyze transition through an adjacent edge
7164     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7165     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7166     gp_Vec edgeAdjacent( p1, p2 );
7167     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7168     bool out2 = (edgeNorm2 * p2int) < -tol;
7169
7170     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7171     return covexCorner ? (out || out2) : (out && out2);
7172   }
7173   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7174   {
7175     // point is out of edge if it is NOT ON any straight part of edge
7176     // (we consider quadratic edge as being composed of two straight parts)
7177     for ( i = 1; i < nbNodes; ++i )
7178     {
7179       gp_Vec edge( xyz[i-1], xyz[i]);
7180       gp_Vec n1p ( xyz[i-1], point);
7181       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7182       if ( dist > tol )
7183         continue;
7184       gp_Vec n2p( xyz[i], point );
7185       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7186         continue;
7187       return false; // point is ON this part
7188     }
7189     return true;
7190   }
7191   // Node or 0D element -------------------------------------------------------------------------
7192   {
7193     gp_Vec n2p ( xyz[0], point );
7194     return n2p.Magnitude() <= tol;
7195   }
7196   return true;
7197 }
7198
7199 //=======================================================================
7200
7201 namespace
7202 {
7203   // Position of a point relative to a segment
7204   //            .           .
7205   //            .  LEFT     .
7206   //            .           .
7207   //  VERTEX 1  o----ON----->  VERTEX 2
7208   //            .           .
7209   //            .  RIGHT    .
7210   //            .           .
7211   enum PositionName { POS_LEFT = 1, POS_VERTEX = 2, POS_RIGHT = 4, //POS_ON = 8,
7212                       POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX };
7213   struct PointPos
7214   {
7215     PositionName _name; 
7216     int          _index; // index of vertex or segment
7217
7218     PointPos( PositionName n, int i=-1 ): _name(n), _index(i) {}
7219     bool operator < (const PointPos& other ) const
7220     {
7221       if ( _name == other._name )
7222         return  ( _index < 0 || other._index < 0 ) ? false : _index < other._index;
7223       return _name < other._name;
7224     }
7225   };
7226
7227   //================================================================================
7228   /*!
7229    * \brief Return of a point relative to a segment
7230    *  \param point2D      - the point to analyze position of
7231    *  \param xyVec        - end points of segments
7232    *  \param index0       - 0-based index of the first point of segment
7233    *  \param posToFindOut - flags of positions to detect
7234    *  \retval PointPos - point position
7235    */
7236   //================================================================================
7237
7238   PointPos getPointPosition( const gp_XY& point2D,
7239                              const gp_XY* segEnds,
7240                              const int    index0 = 0,
7241                              const int    posToFindOut = POS_ALL)
7242   {
7243     const gp_XY& p1 = segEnds[ index0   ];
7244     const gp_XY& p2 = segEnds[ index0+1 ];
7245     const gp_XY grad = p2 - p1;
7246
7247     if ( posToFindOut & POS_VERTEX )
7248     {
7249       // check if the point2D is at "vertex 1" zone
7250       gp_XY pp1[2] = { p1, gp_XY( p1.X() - grad.Y(),
7251                                   p1.Y() + grad.X() ) };
7252       if ( getPointPosition( point2D, pp1, 0, POS_LEFT|POS_RIGHT )._name == POS_LEFT )
7253         return PointPos( POS_VERTEX, index0 );
7254
7255       // check if the point2D is at "vertex 2" zone
7256       gp_XY pp2[2] = { p2, gp_XY( p2.X() - grad.Y(),
7257                                   p2.Y() + grad.X() ) };
7258       if ( getPointPosition( point2D, pp2, 0, POS_LEFT|POS_RIGHT )._name == POS_RIGHT )
7259         return PointPos( POS_VERTEX, index0 + 1);
7260     }
7261     double edgeEquation =
7262       ( point2D.X() - p1.X() ) * grad.Y() - ( point2D.Y() - p1.Y() ) * grad.X();
7263     return PointPos( edgeEquation < 0 ? POS_LEFT : POS_RIGHT, index0 );
7264   }
7265 }
7266
7267 //=======================================================================
7268 /*!
7269  * \brief Return minimal distance from a point to a face
7270  *
7271  * Currently we ignore non-planarity and 2nd order of face
7272  */
7273 //=======================================================================
7274
7275 double SMESH_MeshEditor::GetDistance( const SMDS_MeshFace* face,
7276                                       const gp_Pnt&        point )
7277 {
7278   double badDistance = -1;
7279   if ( !face ) return badDistance;
7280
7281   // coordinates of nodes (medium nodes, if any, ignored)
7282   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
7283   vector<gp_XYZ> xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() );
7284   xyz.resize( face->NbCornerNodes()+1 );
7285
7286   // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis,
7287   // and xyz[2] lies in the XZ plane. This is to pass to 2D space on XZ plane.
7288   gp_Trsf trsf;
7289   gp_Vec OZ ( xyz[0], xyz[1] );
7290   gp_Vec OX ( xyz[0], xyz[2] );
7291   if ( OZ.Magnitude() < std::numeric_limits<double>::min() )
7292   {
7293     if ( xyz.size() < 4 ) return badDistance;
7294     OZ = gp_Vec ( xyz[0], xyz[2] );
7295     OX = gp_Vec ( xyz[0], xyz[3] );
7296   }
7297   gp_Ax3 tgtCS;
7298   try {
7299     tgtCS = gp_Ax3( xyz[0], OZ, OX );
7300   }
7301   catch ( Standard_Failure ) {
7302     return badDistance;
7303   }
7304   trsf.SetTransformation( tgtCS );
7305
7306   // move all the nodes to 2D
7307   vector<gp_XY> xy( xyz.size() );
7308   for ( size_t i = 0;i < xyz.size()-1; ++i )
7309   {
7310     gp_XYZ p3d = xyz[i];
7311     trsf.Transforms( p3d );
7312     xy[i].SetCoord( p3d.X(), p3d.Z() );
7313   }
7314   xyz.back() = xyz.front();
7315   xy.back() = xy.front();
7316
7317   // // move the point in 2D
7318   gp_XYZ tmpPnt = point.XYZ();
7319   trsf.Transforms( tmpPnt );
7320   gp_XY point2D( tmpPnt.X(), tmpPnt.Z() );
7321
7322   // loop on segments of the face to analyze point position ralative to the face
7323   set< PointPos > pntPosSet;
7324   for ( size_t i = 1; i < xy.size(); ++i )
7325   {
7326     PointPos pos = getPointPosition( point2D, &xy[0], i-1 );
7327     pntPosSet.insert( pos );
7328   }
7329
7330   // compute distance
7331   PointPos pos = *pntPosSet.begin();
7332   // cout << "Face " << face->GetID() << " DIST: ";
7333   switch ( pos._name )
7334   {
7335   case POS_LEFT: {
7336     // point is most close to a segment
7337     gp_Vec p0p1( point, xyz[ pos._index ] );
7338     gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector
7339     p1p2.Normalize();
7340     double projDist = p0p1 * p1p2; // distance projected to the segment
7341     gp_Vec projVec = p1p2 * projDist;
7342     gp_Vec distVec = p0p1 - projVec;
7343     // cout << distVec.Magnitude()  << ", SEG " << face->GetNode(pos._index)->GetID()
7344     //      << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl;
7345     return distVec.Magnitude();
7346   }
7347   case POS_RIGHT: {
7348     // point is inside the face
7349     double distToFacePlane = tmpPnt.Y();
7350     // cout << distToFacePlane << ", INSIDE " << endl;
7351     return Abs( distToFacePlane );
7352   }
7353   case POS_VERTEX: {
7354     // point is most close to a node
7355     gp_Vec distVec( point, xyz[ pos._index ]);
7356     // cout << distVec.Magnitude()  << " VERTEX " << face->GetNode(pos._index)->GetID() << endl;
7357     return distVec.Magnitude();
7358   }
7359   }
7360   return badDistance;
7361 }
7362
7363 //=======================================================================
7364 //function : SimplifyFace
7365 //purpose  :
7366 //=======================================================================
7367 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7368                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7369                                     vector<int>&                        quantities) const
7370 {
7371   int nbNodes = faceNodes.size();
7372
7373   if (nbNodes < 3)
7374     return 0;
7375
7376   set<const SMDS_MeshNode*> nodeSet;
7377
7378   // get simple seq of nodes
7379   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7380   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7381   int iSimple = 0, nbUnique = 0;
7382
7383   simpleNodes[iSimple++] = faceNodes[0];
7384   nbUnique++;
7385   for (int iCur = 1; iCur < nbNodes; iCur++) {
7386     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7387       simpleNodes[iSimple++] = faceNodes[iCur];
7388       if (nodeSet.insert( faceNodes[iCur] ).second)
7389         nbUnique++;
7390     }
7391   }
7392   int nbSimple = iSimple;
7393   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7394     nbSimple--;
7395     iSimple--;
7396   }
7397
7398   if (nbUnique < 3)
7399     return 0;
7400
7401   // separate loops
7402   int nbNew = 0;
7403   bool foundLoop = (nbSimple > nbUnique);
7404   while (foundLoop) {
7405     foundLoop = false;
7406     set<const SMDS_MeshNode*> loopSet;
7407     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7408       const SMDS_MeshNode* n = simpleNodes[iSimple];
7409       if (!loopSet.insert( n ).second) {
7410         foundLoop = true;
7411
7412         // separate loop
7413         int iC = 0, curLast = iSimple;
7414         for (; iC < curLast; iC++) {
7415           if (simpleNodes[iC] == n) break;
7416         }
7417         int loopLen = curLast - iC;
7418         if (loopLen > 2) {
7419           // create sub-element
7420           nbNew++;
7421           quantities.push_back(loopLen);
7422           for (; iC < curLast; iC++) {
7423             poly_nodes.push_back(simpleNodes[iC]);
7424           }
7425         }
7426         // shift the rest nodes (place from the first loop position)
7427         for (iC = curLast + 1; iC < nbSimple; iC++) {
7428           simpleNodes[iC - loopLen] = simpleNodes[iC];
7429         }
7430         nbSimple -= loopLen;
7431         iSimple -= loopLen;
7432       }
7433     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7434   } // while (foundLoop)
7435
7436   if (iSimple > 2) {
7437     nbNew++;
7438     quantities.push_back(iSimple);
7439     for (int i = 0; i < iSimple; i++)
7440       poly_nodes.push_back(simpleNodes[i]);
7441   }
7442
7443   return nbNew;
7444 }
7445
7446 //=======================================================================
7447 //function : MergeNodes
7448 //purpose  : In each group, the cdr of nodes are substituted by the first one
7449 //           in all elements.
7450 //=======================================================================
7451
7452 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7453 {
7454   MESSAGE("MergeNodes");
7455   myLastCreatedElems.Clear();
7456   myLastCreatedNodes.Clear();
7457
7458   SMESHDS_Mesh* aMesh = GetMeshDS();
7459
7460   TNodeNodeMap nodeNodeMap; // node to replace - new node
7461   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7462   list< int > rmElemIds, rmNodeIds;
7463
7464   // Fill nodeNodeMap and elems
7465
7466   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7467   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7468     list<const SMDS_MeshNode*>& nodes = *grIt;
7469     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7470     const SMDS_MeshNode* nToKeep = *nIt;
7471     //MESSAGE("node to keep " << nToKeep->GetID());
7472     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7473       const SMDS_MeshNode* nToRemove = *nIt;
7474       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7475       if ( nToRemove != nToKeep ) {
7476         //MESSAGE("  node to remove " << nToRemove->GetID());
7477         rmNodeIds.push_back( nToRemove->GetID() );
7478         AddToSameGroups( nToKeep, nToRemove, aMesh );
7479       }
7480
7481       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7482       while ( invElemIt->more() ) {
7483         const SMDS_MeshElement* elem = invElemIt->next();
7484         elems.insert(elem);
7485       }
7486     }
7487   }
7488   // Change element nodes or remove an element
7489
7490   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7491   for ( ; eIt != elems.end(); eIt++ ) {
7492     const SMDS_MeshElement* elem = *eIt;
7493     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7494     int nbNodes = elem->NbNodes();
7495     int aShapeId = FindShape( elem );
7496
7497     set<const SMDS_MeshNode*> nodeSet;
7498     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7499     int iUnique = 0, iCur = 0, nbRepl = 0;
7500     vector<int> iRepl( nbNodes );
7501
7502     // get new seq of nodes
7503     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7504     while ( itN->more() ) {
7505       const SMDS_MeshNode* n =
7506         static_cast<const SMDS_MeshNode*>( itN->next() );
7507
7508       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7509       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7510         n = (*nnIt).second;
7511         // BUG 0020185: begin
7512         {
7513           bool stopRecur = false;
7514           set<const SMDS_MeshNode*> nodesRecur;
7515           nodesRecur.insert(n);
7516           while (!stopRecur) {
7517             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7518             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7519               n = (*nnIt_i).second;
7520               if (!nodesRecur.insert(n).second) {
7521                 // error: recursive dependancy
7522                 stopRecur = true;
7523               }
7524             }
7525             else
7526               stopRecur = true;
7527           }
7528         }
7529         // BUG 0020185: end
7530       }
7531       curNodes[ iCur ] = n;
7532       bool isUnique = nodeSet.insert( n ).second;
7533       if ( isUnique )
7534         uniqueNodes[ iUnique++ ] = n;
7535       else
7536         iRepl[ nbRepl++ ] = iCur;
7537       iCur++;
7538     }
7539
7540     // Analyse element topology after replacement
7541
7542     bool isOk = true;
7543     int nbUniqueNodes = nodeSet.size();
7544     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7545     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7546       // Polygons and Polyhedral volumes
7547       if (elem->IsPoly()) {
7548
7549         if (elem->GetType() == SMDSAbs_Face) {
7550           // Polygon
7551           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7552           int inode = 0;
7553           for (; inode < nbNodes; inode++) {
7554             face_nodes[inode] = curNodes[inode];
7555           }
7556
7557           vector<const SMDS_MeshNode *> polygons_nodes;
7558           vector<int> quantities;
7559           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7560           if (nbNew > 0) {
7561             inode = 0;
7562             for (int iface = 0; iface < nbNew; iface++) {
7563               int nbNodes = quantities[iface];
7564               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7565               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7566                 poly_nodes[ii] = polygons_nodes[inode];
7567               }
7568               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7569               myLastCreatedElems.Append(newElem);
7570               if (aShapeId)
7571                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7572             }
7573
7574             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7575             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7576             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7577             int quid =0;
7578             if (nbNew > 0) quid = nbNew - 1;
7579             vector<int> newquant(quantities.begin()+quid, quantities.end());
7580             const SMDS_MeshElement* newElem = 0;
7581             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7582             myLastCreatedElems.Append(newElem);
7583             if ( aShapeId && newElem )
7584               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7585             rmElemIds.push_back(elem->GetID());
7586           }
7587           else {
7588             rmElemIds.push_back(elem->GetID());
7589           }
7590
7591         }
7592         else if (elem->GetType() == SMDSAbs_Volume) {
7593           // Polyhedral volume
7594           if (nbUniqueNodes < 4) {
7595             rmElemIds.push_back(elem->GetID());
7596           }
7597           else {
7598             // each face has to be analyzed in order to check volume validity
7599             const SMDS_VtkVolume* aPolyedre =
7600               dynamic_cast<const SMDS_VtkVolume*>( elem );
7601             if (aPolyedre) {
7602               int nbFaces = aPolyedre->NbFaces();
7603
7604               vector<const SMDS_MeshNode *> poly_nodes;
7605               vector<int> quantities;
7606
7607               for (int iface = 1; iface <= nbFaces; iface++) {
7608                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7609                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7610
7611                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7612                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7613                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7614                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7615                     faceNode = (*nnIt).second;
7616                   }
7617                   faceNodes[inode - 1] = faceNode;
7618                 }
7619
7620                 SimplifyFace(faceNodes, poly_nodes, quantities);
7621               }
7622
7623               if (quantities.size() > 3) {
7624                 // to be done: remove coincident faces
7625               }
7626
7627               if (quantities.size() > 3)
7628                 {
7629                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7630                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7631                   const SMDS_MeshElement* newElem = 0;
7632                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7633                   myLastCreatedElems.Append(newElem);
7634                   if ( aShapeId && newElem )
7635                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7636                   rmElemIds.push_back(elem->GetID());
7637                 }
7638             }
7639             else {
7640               rmElemIds.push_back(elem->GetID());
7641             }
7642           }
7643         }
7644         else {
7645         }
7646
7647         continue;
7648       } // poly element
7649
7650       // Regular elements
7651       // TODO not all the possible cases are solved. Find something more generic?
7652       switch ( nbNodes ) {
7653       case 2: ///////////////////////////////////// EDGE
7654         isOk = false; break;
7655       case 3: ///////////////////////////////////// TRIANGLE
7656         isOk = false; break;
7657       case 4:
7658         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7659           isOk = false;
7660         else { //////////////////////////////////// QUADRANGLE
7661           if ( nbUniqueNodes < 3 )
7662             isOk = false;
7663           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7664             isOk = false; // opposite nodes stick
7665           //MESSAGE("isOk " << isOk);
7666         }
7667         break;
7668       case 6: ///////////////////////////////////// PENTAHEDRON
7669         if ( nbUniqueNodes == 4 ) {
7670           // ---------------------------------> tetrahedron
7671           if (nbRepl == 3 &&
7672               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7673             // all top nodes stick: reverse a bottom
7674             uniqueNodes[ 0 ] = curNodes [ 1 ];
7675             uniqueNodes[ 1 ] = curNodes [ 0 ];
7676           }
7677           else if (nbRepl == 3 &&
7678                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7679             // all bottom nodes stick: set a top before
7680             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7681             uniqueNodes[ 0 ] = curNodes [ 3 ];
7682             uniqueNodes[ 1 ] = curNodes [ 4 ];
7683             uniqueNodes[ 2 ] = curNodes [ 5 ];
7684           }
7685           else if (nbRepl == 4 &&
7686                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7687             // a lateral face turns into a line: reverse a bottom
7688             uniqueNodes[ 0 ] = curNodes [ 1 ];
7689             uniqueNodes[ 1 ] = curNodes [ 0 ];
7690           }
7691           else
7692             isOk = false;
7693         }
7694         else if ( nbUniqueNodes == 5 ) {
7695           // PENTAHEDRON --------------------> 2 tetrahedrons
7696           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7697             // a bottom node sticks with a linked top one
7698             // 1.
7699             SMDS_MeshElement* newElem =
7700               aMesh->AddVolume(curNodes[ 3 ],
7701                                curNodes[ 4 ],
7702                                curNodes[ 5 ],
7703                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7704             myLastCreatedElems.Append(newElem);
7705             if ( aShapeId )
7706               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7707             // 2. : reverse a bottom
7708             uniqueNodes[ 0 ] = curNodes [ 1 ];
7709             uniqueNodes[ 1 ] = curNodes [ 0 ];
7710             nbUniqueNodes = 4;
7711           }
7712           else
7713             isOk = false;
7714         }
7715         else
7716           isOk = false;
7717         break;
7718       case 8: {
7719         if(elem->IsQuadratic()) { // Quadratic quadrangle
7720           //   1    5    2
7721           //    +---+---+
7722           //    |       |
7723           //    |       |
7724           //   4+       +6
7725           //    |       |
7726           //    |       |
7727           //    +---+---+
7728           //   0    7    3
7729           isOk = false;
7730           if(nbRepl==2) {
7731             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7732           }
7733           if(nbRepl==3) {
7734             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7735             nbUniqueNodes = 6;
7736             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7737               uniqueNodes[0] = curNodes[0];
7738               uniqueNodes[1] = curNodes[2];
7739               uniqueNodes[2] = curNodes[3];
7740               uniqueNodes[3] = curNodes[5];
7741               uniqueNodes[4] = curNodes[6];
7742               uniqueNodes[5] = curNodes[7];
7743               isOk = true;
7744             }
7745             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7746               uniqueNodes[0] = curNodes[0];
7747               uniqueNodes[1] = curNodes[1];
7748               uniqueNodes[2] = curNodes[2];
7749               uniqueNodes[3] = curNodes[4];
7750               uniqueNodes[4] = curNodes[5];
7751               uniqueNodes[5] = curNodes[6];
7752               isOk = true;
7753             }
7754             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7755               uniqueNodes[0] = curNodes[1];
7756               uniqueNodes[1] = curNodes[2];
7757               uniqueNodes[2] = curNodes[3];
7758               uniqueNodes[3] = curNodes[5];
7759               uniqueNodes[4] = curNodes[6];
7760               uniqueNodes[5] = curNodes[0];
7761               isOk = true;
7762             }
7763             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7764               uniqueNodes[0] = curNodes[0];
7765               uniqueNodes[1] = curNodes[1];
7766               uniqueNodes[2] = curNodes[3];
7767               uniqueNodes[3] = curNodes[4];
7768               uniqueNodes[4] = curNodes[6];
7769               uniqueNodes[5] = curNodes[7];
7770               isOk = true;
7771             }
7772             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7773               uniqueNodes[0] = curNodes[0];
7774               uniqueNodes[1] = curNodes[2];
7775               uniqueNodes[2] = curNodes[3];
7776               uniqueNodes[3] = curNodes[1];
7777               uniqueNodes[4] = curNodes[6];
7778               uniqueNodes[5] = curNodes[7];
7779               isOk = true;
7780             }
7781             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7782               uniqueNodes[0] = curNodes[0];
7783               uniqueNodes[1] = curNodes[1];
7784               uniqueNodes[2] = curNodes[2];
7785               uniqueNodes[3] = curNodes[4];
7786               uniqueNodes[4] = curNodes[5];
7787               uniqueNodes[5] = curNodes[7];
7788               isOk = true;
7789             }
7790             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7791               uniqueNodes[0] = curNodes[0];
7792               uniqueNodes[1] = curNodes[1];
7793               uniqueNodes[2] = curNodes[3];
7794               uniqueNodes[3] = curNodes[4];
7795               uniqueNodes[4] = curNodes[2];
7796               uniqueNodes[5] = curNodes[7];
7797               isOk = true;
7798             }
7799             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7800               uniqueNodes[0] = curNodes[0];
7801               uniqueNodes[1] = curNodes[1];
7802               uniqueNodes[2] = curNodes[2];
7803               uniqueNodes[3] = curNodes[4];
7804               uniqueNodes[4] = curNodes[5];
7805               uniqueNodes[5] = curNodes[3];
7806               isOk = true;
7807             }
7808           }
7809           if(nbRepl==4) {
7810             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7811           }
7812           if(nbRepl==5) {
7813             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7814           }
7815           break;
7816         }
7817         //////////////////////////////////// HEXAHEDRON
7818         isOk = false;
7819         SMDS_VolumeTool hexa (elem);
7820         hexa.SetExternalNormal();
7821         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7822           //////////////////////// HEX ---> 1 tetrahedron
7823           for ( int iFace = 0; iFace < 6; iFace++ ) {
7824             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7825             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7826                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7827                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7828               // one face turns into a point ...
7829               int iOppFace = hexa.GetOppFaceIndex( iFace );
7830               ind = hexa.GetFaceNodesIndices( iOppFace );
7831               int nbStick = 0;
7832               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7833                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7834                   nbStick++;
7835               }
7836               if ( nbStick == 1 ) {
7837                 // ... and the opposite one - into a triangle.
7838                 // set a top node
7839                 ind = hexa.GetFaceNodesIndices( iFace );
7840                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7841                 isOk = true;
7842               }
7843               break;
7844             }
7845           }
7846         }
7847         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7848           //////////////////////// HEX ---> 1 prism
7849           int nbTria = 0, iTria[3];
7850           const int *ind; // indices of face nodes
7851           // look for triangular faces
7852           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7853             ind = hexa.GetFaceNodesIndices( iFace );
7854             TIDSortedNodeSet faceNodes;
7855             for ( iCur = 0; iCur < 4; iCur++ )
7856               faceNodes.insert( curNodes[ind[iCur]] );
7857             if ( faceNodes.size() == 3 )
7858               iTria[ nbTria++ ] = iFace;
7859           }
7860           // check if triangles are opposite
7861           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7862           {
7863             isOk = true;
7864             // set nodes of the bottom triangle
7865             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7866             vector<int> indB;
7867             for ( iCur = 0; iCur < 4; iCur++ )
7868               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7869                 indB.push_back( ind[iCur] );
7870             if ( !hexa.IsForward() )
7871               std::swap( indB[0], indB[2] );
7872             for ( iCur = 0; iCur < 3; iCur++ )
7873               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7874             // set nodes of the top triangle
7875             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7876             for ( iCur = 0; iCur < 3; ++iCur )
7877               for ( int j = 0; j < 4; ++j )
7878                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7879                 {
7880                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7881                   break;
7882                 }
7883           }
7884           break;
7885         }
7886         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7887           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7888           for ( int iFace = 0; iFace < 6; iFace++ ) {
7889             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7890             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7891                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7892                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7893               // one face turns into a point ...
7894               int iOppFace = hexa.GetOppFaceIndex( iFace );
7895               ind = hexa.GetFaceNodesIndices( iOppFace );
7896               int nbStick = 0;
7897               iUnique = 2;  // reverse a tetrahedron 1 bottom
7898               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7899                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7900                   nbStick++;
7901                 else if ( iUnique >= 0 )
7902                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7903               }
7904               if ( nbStick == 0 ) {
7905                 // ... and the opposite one is a quadrangle
7906                 // set a top node
7907                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7908                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7909                 nbUniqueNodes = 4;
7910                 // tetrahedron 2
7911                 SMDS_MeshElement* newElem =
7912                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7913                                    curNodes[ind[ 3 ]],
7914                                    curNodes[ind[ 2 ]],
7915                                    curNodes[indTop[ 0 ]]);
7916                 myLastCreatedElems.Append(newElem);
7917                 if ( aShapeId )
7918                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7919                 isOk = true;
7920               }
7921               break;
7922             }
7923           }
7924         }
7925         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7926           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7927           // find indices of quad and tri faces
7928           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7929           for ( iFace = 0; iFace < 6; iFace++ ) {
7930             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7931             nodeSet.clear();
7932             for ( iCur = 0; iCur < 4; iCur++ )
7933               nodeSet.insert( curNodes[ind[ iCur ]] );
7934             nbUniqueNodes = nodeSet.size();
7935             if ( nbUniqueNodes == 3 )
7936               iTriFace[ nbTri++ ] = iFace;
7937             else if ( nbUniqueNodes == 4 )
7938               iQuadFace[ nbQuad++ ] = iFace;
7939           }
7940           if (nbQuad == 2 && nbTri == 4 &&
7941               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7942             // 2 opposite quadrangles stuck with a diagonal;
7943             // sample groups of merged indices: (0-4)(2-6)
7944             // --------------------------------------------> 2 tetrahedrons
7945             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7946             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7947             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7948             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7949                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7950               // stuck with 0-2 diagonal
7951               i0  = ind1[ 3 ];
7952               i1d = ind1[ 0 ];
7953               i2  = ind1[ 1 ];
7954               i3d = ind1[ 2 ];
7955               i0t = ind2[ 1 ];
7956               i2t = ind2[ 3 ];
7957             }
7958             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7959                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7960               // stuck with 1-3 diagonal
7961               i0  = ind1[ 0 ];
7962               i1d = ind1[ 1 ];
7963               i2  = ind1[ 2 ];
7964               i3d = ind1[ 3 ];
7965               i0t = ind2[ 0 ];
7966               i2t = ind2[ 1 ];
7967             }
7968             else {
7969               ASSERT(0);
7970             }
7971             // tetrahedron 1
7972             uniqueNodes[ 0 ] = curNodes [ i0 ];
7973             uniqueNodes[ 1 ] = curNodes [ i1d ];
7974             uniqueNodes[ 2 ] = curNodes [ i3d ];
7975             uniqueNodes[ 3 ] = curNodes [ i0t ];
7976             nbUniqueNodes = 4;
7977             // tetrahedron 2
7978             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7979                                                          curNodes[ i2 ],
7980                                                          curNodes[ i3d ],
7981                                                          curNodes[ i2t ]);
7982             myLastCreatedElems.Append(newElem);
7983             if ( aShapeId )
7984               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7985             isOk = true;
7986           }
7987           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7988                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7989             // --------------------------------------------> prism
7990             // find 2 opposite triangles
7991             nbUniqueNodes = 6;
7992             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7993               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7994                 // find indices of kept and replaced nodes
7995                 // and fill unique nodes of 2 opposite triangles
7996                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7997                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7998                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7999                 // fill unique nodes
8000                 iUnique = 0;
8001                 isOk = true;
8002                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
8003                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
8004                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
8005                   if ( n == nInit ) {
8006                     // iCur of a linked node of the opposite face (make normals co-directed):
8007                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
8008                     // check that correspondent corners of triangles are linked
8009                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
8010                       isOk = false;
8011                     else {
8012                       uniqueNodes[ iUnique ] = n;
8013                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
8014                       iUnique++;
8015                     }
8016                   }
8017                 }
8018                 break;
8019               }
8020             }
8021           }
8022         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
8023         else
8024         {
8025           MESSAGE("MergeNodes() removes hexahedron "<< elem);
8026         }
8027         break;
8028       } // HEXAHEDRON
8029
8030       default:
8031         isOk = false;
8032       } // switch ( nbNodes )
8033
8034     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
8035
8036     if ( isOk ) { // the elem remains valid after sticking nodes
8037       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
8038       {
8039         // Change nodes of polyedre
8040         const SMDS_VtkVolume* aPolyedre =
8041           dynamic_cast<const SMDS_VtkVolume*>( elem );
8042         if (aPolyedre) {
8043           int nbFaces = aPolyedre->NbFaces();
8044
8045           vector<const SMDS_MeshNode *> poly_nodes;
8046           vector<int> quantities (nbFaces);
8047
8048           for (int iface = 1; iface <= nbFaces; iface++) {
8049             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
8050             quantities[iface - 1] = nbFaceNodes;
8051
8052             for (inode = 1; inode <= nbFaceNodes; inode++) {
8053               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
8054
8055               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
8056               if (nnIt != nodeNodeMap.end()) { // curNode sticks
8057                 curNode = (*nnIt).second;
8058               }
8059               poly_nodes.push_back(curNode);
8060             }
8061           }
8062           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
8063         }
8064       }
8065       else // replace non-polyhedron elements
8066       {
8067         const SMDSAbs_ElementType etyp = elem->GetType();
8068         const int elemId               = elem->GetID();
8069         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
8070         uniqueNodes.resize(nbUniqueNodes);
8071
8072         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
8073
8074         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
8075         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
8076         if ( sm && newElem )
8077           sm->AddElement( newElem );
8078         if ( elem != newElem )
8079           ReplaceElemInGroups( elem, newElem, aMesh );
8080       }
8081     }
8082     else {
8083       // Remove invalid regular element or invalid polygon
8084       rmElemIds.push_back( elem->GetID() );
8085     }
8086
8087   } // loop on elements
8088
8089   // Remove bad elements, then equal nodes (order important)
8090
8091   Remove( rmElemIds, false );
8092   Remove( rmNodeIds, true );
8093
8094 }
8095
8096
8097 // ========================================================
8098 // class   : SortableElement
8099 // purpose : allow sorting elements basing on their nodes
8100 // ========================================================
8101 class SortableElement : public set <const SMDS_MeshElement*>
8102 {
8103 public:
8104
8105   SortableElement( const SMDS_MeshElement* theElem )
8106   {
8107     myElem = theElem;
8108     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
8109     while ( nodeIt->more() )
8110       this->insert( nodeIt->next() );
8111   }
8112
8113   const SMDS_MeshElement* Get() const
8114   { return myElem; }
8115
8116   void Set(const SMDS_MeshElement* e) const
8117   { myElem = e; }
8118
8119
8120 private:
8121   mutable const SMDS_MeshElement* myElem;
8122 };
8123
8124 //=======================================================================
8125 //function : FindEqualElements
8126 //purpose  : Return list of group of elements built on the same nodes.
8127 //           Search among theElements or in the whole mesh if theElements is empty
8128 //=======================================================================
8129 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
8130                                          TListOfListOfElementsID &      theGroupsOfElementsID)
8131 {
8132   myLastCreatedElems.Clear();
8133   myLastCreatedNodes.Clear();
8134
8135   typedef set<const SMDS_MeshElement*> TElemsSet;
8136   typedef map< SortableElement, int > TMapOfNodeSet;
8137   typedef list<int> TGroupOfElems;
8138
8139   TElemsSet elems;
8140   if ( theElements.empty() )
8141   { // get all elements in the mesh
8142     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
8143     while ( eIt->more() )
8144       elems.insert( elems.end(), eIt->next());
8145   }
8146   else
8147     elems = theElements;
8148
8149   vector< TGroupOfElems > arrayOfGroups;
8150   TGroupOfElems groupOfElems;
8151   TMapOfNodeSet mapOfNodeSet;
8152
8153   TElemsSet::iterator elemIt = elems.begin();
8154   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
8155     const SMDS_MeshElement* curElem = *elemIt;
8156     SortableElement SE(curElem);
8157     int ind = -1;
8158     // check uniqueness
8159     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
8160     if( !(pp.second) ) {
8161       TMapOfNodeSet::iterator& itSE = pp.first;
8162       ind = (*itSE).second;
8163       arrayOfGroups[ind].push_back(curElem->GetID());
8164     }
8165     else {
8166       groupOfElems.clear();
8167       groupOfElems.push_back(curElem->GetID());
8168       arrayOfGroups.push_back(groupOfElems);
8169       i++;
8170     }
8171   }
8172
8173   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
8174   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8175     groupOfElems = *groupIt;
8176     if ( groupOfElems.size() > 1 ) {
8177       groupOfElems.sort();
8178       theGroupsOfElementsID.push_back(groupOfElems);
8179     }
8180   }
8181 }
8182
8183 //=======================================================================
8184 //function : MergeElements
8185 //purpose  : In each given group, substitute all elements by the first one.
8186 //=======================================================================
8187
8188 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8189 {
8190   myLastCreatedElems.Clear();
8191   myLastCreatedNodes.Clear();
8192
8193   typedef list<int> TListOfIDs;
8194   TListOfIDs rmElemIds; // IDs of elems to remove
8195
8196   SMESHDS_Mesh* aMesh = GetMeshDS();
8197
8198   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8199   while ( groupsIt != theGroupsOfElementsID.end() ) {
8200     TListOfIDs& aGroupOfElemID = *groupsIt;
8201     aGroupOfElemID.sort();
8202     int elemIDToKeep = aGroupOfElemID.front();
8203     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8204     aGroupOfElemID.pop_front();
8205     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8206     while ( idIt != aGroupOfElemID.end() ) {
8207       int elemIDToRemove = *idIt;
8208       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8209       // add the kept element in groups of removed one (PAL15188)
8210       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8211       rmElemIds.push_back( elemIDToRemove );
8212       ++idIt;
8213     }
8214     ++groupsIt;
8215   }
8216
8217   Remove( rmElemIds, false );
8218 }
8219
8220 //=======================================================================
8221 //function : MergeEqualElements
8222 //purpose  : Remove all but one of elements built on the same nodes.
8223 //=======================================================================
8224
8225 void SMESH_MeshEditor::MergeEqualElements()
8226 {
8227   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8228                                                  to merge equal elements in the whole mesh */
8229   TListOfListOfElementsID aGroupsOfElementsID;
8230   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8231   MergeElements(aGroupsOfElementsID);
8232 }
8233
8234 //=======================================================================
8235 //function : FindFaceInSet
8236 //purpose  : Return a face having linked nodes n1 and n2 and which is
8237 //           - not in avoidSet,
8238 //           - in elemSet provided that !elemSet.empty()
8239 //           i1 and i2 optionally returns indices of n1 and n2
8240 //=======================================================================
8241
8242 const SMDS_MeshElement*
8243 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8244                                 const SMDS_MeshNode*    n2,
8245                                 const TIDSortedElemSet& elemSet,
8246                                 const TIDSortedElemSet& avoidSet,
8247                                 int*                    n1ind,
8248                                 int*                    n2ind)
8249
8250 {
8251   int i1, i2;
8252   const SMDS_MeshElement* face = 0;
8253
8254   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8255   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8256   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8257   {
8258     //MESSAGE("in while ( invElemIt->more() && !face )");
8259     const SMDS_MeshElement* elem = invElemIt->next();
8260     if (avoidSet.count( elem ))
8261       continue;
8262     if ( !elemSet.empty() && !elemSet.count( elem ))
8263       continue;
8264     // index of n1
8265     i1 = elem->GetNodeIndex( n1 );
8266     // find a n2 linked to n1
8267     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8268     for ( int di = -1; di < 2 && !face; di += 2 )
8269     {
8270       i2 = (i1+di+nbN) % nbN;
8271       if ( elem->GetNode( i2 ) == n2 )
8272         face = elem;
8273     }
8274     if ( !face && elem->IsQuadratic())
8275     {
8276       // analysis for quadratic elements using all nodes
8277       const SMDS_VtkFace* F =
8278         dynamic_cast<const SMDS_VtkFace*>(elem);
8279       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8280       // use special nodes iterator
8281       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8282       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8283       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8284       {
8285         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8286         if ( n1 == prevN && n2 == n )
8287         {
8288           face = elem;
8289         }
8290         else if ( n2 == prevN && n1 == n )
8291         {
8292           face = elem; swap( i1, i2 );
8293         }
8294         prevN = n;
8295       }
8296     }
8297   }
8298   if ( n1ind ) *n1ind = i1;
8299   if ( n2ind ) *n2ind = i2;
8300   return face;
8301 }
8302
8303 //=======================================================================
8304 //function : findAdjacentFace
8305 //purpose  :
8306 //=======================================================================
8307
8308 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8309                                                 const SMDS_MeshNode* n2,
8310                                                 const SMDS_MeshElement* elem)
8311 {
8312   TIDSortedElemSet elemSet, avoidSet;
8313   if ( elem )
8314     avoidSet.insert ( elem );
8315   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8316 }
8317
8318 //=======================================================================
8319 //function : FindFreeBorder
8320 //purpose  :
8321 //=======================================================================
8322
8323 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8324
8325 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8326                                        const SMDS_MeshNode*             theSecondNode,
8327                                        const SMDS_MeshNode*             theLastNode,
8328                                        list< const SMDS_MeshNode* > &   theNodes,
8329                                        list< const SMDS_MeshElement* >& theFaces)
8330 {
8331   if ( !theFirstNode || !theSecondNode )
8332     return false;
8333   // find border face between theFirstNode and theSecondNode
8334   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8335   if ( !curElem )
8336     return false;
8337
8338   theFaces.push_back( curElem );
8339   theNodes.push_back( theFirstNode );
8340   theNodes.push_back( theSecondNode );
8341
8342   //vector<const SMDS_MeshNode*> nodes;
8343   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8344   TIDSortedElemSet foundElems;
8345   bool needTheLast = ( theLastNode != 0 );
8346
8347   while ( nStart != theLastNode ) {
8348     if ( nStart == theFirstNode )
8349       return !needTheLast;
8350
8351     // find all free border faces sharing form nStart
8352
8353     list< const SMDS_MeshElement* > curElemList;
8354     list< const SMDS_MeshNode* > nStartList;
8355     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8356     while ( invElemIt->more() ) {
8357       const SMDS_MeshElement* e = invElemIt->next();
8358       if ( e == curElem || foundElems.insert( e ).second ) {
8359         // get nodes
8360         int iNode = 0, nbNodes = e->NbNodes();
8361         //const SMDS_MeshNode* nodes[nbNodes+1];
8362         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8363
8364         if(e->IsQuadratic()) {
8365           const SMDS_VtkFace* F =
8366             dynamic_cast<const SMDS_VtkFace*>(e);
8367           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8368           // use special nodes iterator
8369           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8370           while( anIter->more() ) {
8371             nodes[ iNode++ ] = cast2Node(anIter->next());
8372           }
8373         }
8374         else {
8375           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8376           while ( nIt->more() )
8377             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8378         }
8379         nodes[ iNode ] = nodes[ 0 ];
8380         // check 2 links
8381         for ( iNode = 0; iNode < nbNodes; iNode++ )
8382           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8383                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8384               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8385           {
8386             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8387             curElemList.push_back( e );
8388           }
8389       }
8390     }
8391     // analyse the found
8392
8393     int nbNewBorders = curElemList.size();
8394     if ( nbNewBorders == 0 ) {
8395       // no free border furthermore
8396       return !needTheLast;
8397     }
8398     else if ( nbNewBorders == 1 ) {
8399       // one more element found
8400       nIgnore = nStart;
8401       nStart = nStartList.front();
8402       curElem = curElemList.front();
8403       theFaces.push_back( curElem );
8404       theNodes.push_back( nStart );
8405     }
8406     else {
8407       // several continuations found
8408       list< const SMDS_MeshElement* >::iterator curElemIt;
8409       list< const SMDS_MeshNode* >::iterator nStartIt;
8410       // check if one of them reached the last node
8411       if ( needTheLast ) {
8412         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8413              curElemIt!= curElemList.end();
8414              curElemIt++, nStartIt++ )
8415           if ( *nStartIt == theLastNode ) {
8416             theFaces.push_back( *curElemIt );
8417             theNodes.push_back( *nStartIt );
8418             return true;
8419           }
8420       }
8421       // find the best free border by the continuations
8422       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8423       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8424       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8425            curElemIt!= curElemList.end();
8426            curElemIt++, nStartIt++ )
8427       {
8428         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8429         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8430         // find one more free border
8431         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8432           cNL->clear();
8433           cFL->clear();
8434         }
8435         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8436           // choice: clear a worse one
8437           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8438           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8439           contNodes[ iWorse ].clear();
8440           contFaces[ iWorse ].clear();
8441         }
8442       }
8443       if ( contNodes[0].empty() && contNodes[1].empty() )
8444         return false;
8445
8446       // append the best free border
8447       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8448       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8449       theNodes.pop_back(); // remove nIgnore
8450       theNodes.pop_back(); // remove nStart
8451       theFaces.pop_back(); // remove curElem
8452       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8453       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8454       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8455       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8456       return true;
8457
8458     } // several continuations found
8459   } // while ( nStart != theLastNode )
8460
8461   return true;
8462 }
8463
8464 //=======================================================================
8465 //function : CheckFreeBorderNodes
8466 //purpose  : Return true if the tree nodes are on a free border
8467 //=======================================================================
8468
8469 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8470                                             const SMDS_MeshNode* theNode2,
8471                                             const SMDS_MeshNode* theNode3)
8472 {
8473   list< const SMDS_MeshNode* > nodes;
8474   list< const SMDS_MeshElement* > faces;
8475   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8476 }
8477
8478 //=======================================================================
8479 //function : SewFreeBorder
8480 //purpose  :
8481 //=======================================================================
8482
8483 SMESH_MeshEditor::Sew_Error
8484 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8485                                  const SMDS_MeshNode* theBordSecondNode,
8486                                  const SMDS_MeshNode* theBordLastNode,
8487                                  const SMDS_MeshNode* theSideFirstNode,
8488                                  const SMDS_MeshNode* theSideSecondNode,
8489                                  const SMDS_MeshNode* theSideThirdNode,
8490                                  const bool           theSideIsFreeBorder,
8491                                  const bool           toCreatePolygons,
8492                                  const bool           toCreatePolyedrs)
8493 {
8494   myLastCreatedElems.Clear();
8495   myLastCreatedNodes.Clear();
8496
8497   MESSAGE("::SewFreeBorder()");
8498   Sew_Error aResult = SEW_OK;
8499
8500   // ====================================
8501   //    find side nodes and elements
8502   // ====================================
8503
8504   list< const SMDS_MeshNode* > nSide[ 2 ];
8505   list< const SMDS_MeshElement* > eSide[ 2 ];
8506   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8507   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8508
8509   // Free border 1
8510   // --------------
8511   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8512                       nSide[0], eSide[0])) {
8513     MESSAGE(" Free Border 1 not found " );
8514     aResult = SEW_BORDER1_NOT_FOUND;
8515   }
8516   if (theSideIsFreeBorder) {
8517     // Free border 2
8518     // --------------
8519     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8520                         nSide[1], eSide[1])) {
8521       MESSAGE(" Free Border 2 not found " );
8522       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8523     }
8524   }
8525   if ( aResult != SEW_OK )
8526     return aResult;
8527
8528   if (!theSideIsFreeBorder) {
8529     // Side 2
8530     // --------------
8531
8532     // -------------------------------------------------------------------------
8533     // Algo:
8534     // 1. If nodes to merge are not coincident, move nodes of the free border
8535     //    from the coord sys defined by the direction from the first to last
8536     //    nodes of the border to the correspondent sys of the side 2
8537     // 2. On the side 2, find the links most co-directed with the correspondent
8538     //    links of the free border
8539     // -------------------------------------------------------------------------
8540
8541     // 1. Since sewing may break if there are volumes to split on the side 2,
8542     //    we wont move nodes but just compute new coordinates for them
8543     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8544     TNodeXYZMap nBordXYZ;
8545     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8546     list< const SMDS_MeshNode* >::iterator nBordIt;
8547
8548     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8549     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8550     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8551     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8552     double tol2 = 1.e-8;
8553     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8554     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8555       // Need node movement.
8556
8557       // find X and Z axes to create trsf
8558       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8559       gp_Vec X = Zs ^ Zb;
8560       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8561         // Zb || Zs
8562         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8563
8564       // coord systems
8565       gp_Ax3 toBordAx( Pb1, Zb, X );
8566       gp_Ax3 fromSideAx( Ps1, Zs, X );
8567       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8568       // set trsf
8569       gp_Trsf toBordSys, fromSide2Sys;
8570       toBordSys.SetTransformation( toBordAx );
8571       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8572       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8573
8574       // move
8575       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8576         const SMDS_MeshNode* n = *nBordIt;
8577         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8578         toBordSys.Transforms( xyz );
8579         fromSide2Sys.Transforms( xyz );
8580         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8581       }
8582     }
8583     else {
8584       // just insert nodes XYZ in the nBordXYZ map
8585       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8586         const SMDS_MeshNode* n = *nBordIt;
8587         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8588       }
8589     }
8590
8591     // 2. On the side 2, find the links most co-directed with the correspondent
8592     //    links of the free border
8593
8594     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8595     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8596     sideNodes.push_back( theSideFirstNode );
8597
8598     bool hasVolumes = false;
8599     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8600     set<long> foundSideLinkIDs, checkedLinkIDs;
8601     SMDS_VolumeTool volume;
8602     //const SMDS_MeshNode* faceNodes[ 4 ];
8603
8604     const SMDS_MeshNode*    sideNode;
8605     const SMDS_MeshElement* sideElem;
8606     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8607     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8608     nBordIt = bordNodes.begin();
8609     nBordIt++;
8610     // border node position and border link direction to compare with
8611     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8612     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8613     // choose next side node by link direction or by closeness to
8614     // the current border node:
8615     bool searchByDir = ( *nBordIt != theBordLastNode );
8616     do {
8617       // find the next node on the Side 2
8618       sideNode = 0;
8619       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8620       long linkID;
8621       checkedLinkIDs.clear();
8622       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8623
8624       // loop on inverse elements of current node (prevSideNode) on the Side 2
8625       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8626       while ( invElemIt->more() )
8627       {
8628         const SMDS_MeshElement* elem = invElemIt->next();
8629         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8630         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8631         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8632         bool isVolume = volume.Set( elem );
8633         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8634         if ( isVolume ) // --volume
8635           hasVolumes = true;
8636         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8637           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8638           if(elem->IsQuadratic()) {
8639             const SMDS_VtkFace* F =
8640               dynamic_cast<const SMDS_VtkFace*>(elem);
8641             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8642             // use special nodes iterator
8643             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8644             while( anIter->more() ) {
8645               nodes[ iNode ] = cast2Node(anIter->next());
8646               if ( nodes[ iNode++ ] == prevSideNode )
8647                 iPrevNode = iNode - 1;
8648             }
8649           }
8650           else {
8651             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8652             while ( nIt->more() ) {
8653               nodes[ iNode ] = cast2Node( nIt->next() );
8654               if ( nodes[ iNode++ ] == prevSideNode )
8655                 iPrevNode = iNode - 1;
8656             }
8657           }
8658           // there are 2 links to check
8659           nbNodes = 2;
8660         }
8661         else // --edge
8662           continue;
8663         // loop on links, to be precise, on the second node of links
8664         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8665           const SMDS_MeshNode* n = nodes[ iNode ];
8666           if ( isVolume ) {
8667             if ( !volume.IsLinked( n, prevSideNode ))
8668               continue;
8669           }
8670           else {
8671             if ( iNode ) // a node before prevSideNode
8672               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8673             else         // a node after prevSideNode
8674               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8675           }
8676           // check if this link was already used
8677           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8678           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8679           if (!isJustChecked &&
8680               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8681           {
8682             // test a link geometrically
8683             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8684             bool linkIsBetter = false;
8685             double dot = 0.0, dist = 0.0;
8686             if ( searchByDir ) { // choose most co-directed link
8687               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8688               linkIsBetter = ( dot > maxDot );
8689             }
8690             else { // choose link with the node closest to bordPos
8691               dist = ( nextXYZ - bordPos ).SquareModulus();
8692               linkIsBetter = ( dist < minDist );
8693             }
8694             if ( linkIsBetter ) {
8695               maxDot = dot;
8696               minDist = dist;
8697               linkID = iLink;
8698               sideNode = n;
8699               sideElem = elem;
8700             }
8701           }
8702         }
8703       } // loop on inverse elements of prevSideNode
8704
8705       if ( !sideNode ) {
8706         MESSAGE(" Cant find path by links of the Side 2 ");
8707         return SEW_BAD_SIDE_NODES;
8708       }
8709       sideNodes.push_back( sideNode );
8710       sideElems.push_back( sideElem );
8711       foundSideLinkIDs.insert ( linkID );
8712       prevSideNode = sideNode;
8713
8714       if ( *nBordIt == theBordLastNode )
8715         searchByDir = false;
8716       else {
8717         // find the next border link to compare with
8718         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8719         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8720         // move to next border node if sideNode is before forward border node (bordPos)
8721         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8722           prevBordNode = *nBordIt;
8723           nBordIt++;
8724           bordPos = nBordXYZ[ *nBordIt ];
8725           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8726           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8727         }
8728       }
8729     }
8730     while ( sideNode != theSideSecondNode );
8731
8732     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8733       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8734       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8735     }
8736   } // end nodes search on the side 2
8737
8738   // ============================
8739   // sew the border to the side 2
8740   // ============================
8741
8742   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8743   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8744
8745   TListOfListOfNodes nodeGroupsToMerge;
8746   if ( nbNodes[0] == nbNodes[1] ||
8747        ( theSideIsFreeBorder && !theSideThirdNode)) {
8748
8749     // all nodes are to be merged
8750
8751     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8752          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8753          nIt[0]++, nIt[1]++ )
8754     {
8755       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8756       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8757       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8758     }
8759   }
8760   else {
8761
8762     // insert new nodes into the border and the side to get equal nb of segments
8763
8764     // get normalized parameters of nodes on the borders
8765     //double param[ 2 ][ maxNbNodes ];
8766     double* param[ 2 ];
8767     param[0] = new double [ maxNbNodes ];
8768     param[1] = new double [ maxNbNodes ];
8769     int iNode, iBord;
8770     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8771       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8772       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8773       const SMDS_MeshNode* nPrev = *nIt;
8774       double bordLength = 0;
8775       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8776         const SMDS_MeshNode* nCur = *nIt;
8777         gp_XYZ segment (nCur->X() - nPrev->X(),
8778                         nCur->Y() - nPrev->Y(),
8779                         nCur->Z() - nPrev->Z());
8780         double segmentLen = segment.Modulus();
8781         bordLength += segmentLen;
8782         param[ iBord ][ iNode ] = bordLength;
8783         nPrev = nCur;
8784       }
8785       // normalize within [0,1]
8786       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8787         param[ iBord ][ iNode ] /= bordLength;
8788       }
8789     }
8790
8791     // loop on border segments
8792     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8793     int i[ 2 ] = { 0, 0 };
8794     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8795     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8796
8797     TElemOfNodeListMap insertMap;
8798     TElemOfNodeListMap::iterator insertMapIt;
8799     // insertMap is
8800     // key:   elem to insert nodes into
8801     // value: 2 nodes to insert between + nodes to be inserted
8802     do {
8803       bool next[ 2 ] = { false, false };
8804
8805       // find min adjacent segment length after sewing
8806       double nextParam = 10., prevParam = 0;
8807       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8808         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8809           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8810         if ( i[ iBord ] > 0 )
8811           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8812       }
8813       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8814       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8815       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8816
8817       // choose to insert or to merge nodes
8818       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8819       if ( Abs( du ) <= minSegLen * 0.2 ) {
8820         // merge
8821         // ------
8822         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8823         const SMDS_MeshNode* n0 = *nIt[0];
8824         const SMDS_MeshNode* n1 = *nIt[1];
8825         nodeGroupsToMerge.back().push_back( n1 );
8826         nodeGroupsToMerge.back().push_back( n0 );
8827         // position of node of the border changes due to merge
8828         param[ 0 ][ i[0] ] += du;
8829         // move n1 for the sake of elem shape evaluation during insertion.
8830         // n1 will be removed by MergeNodes() anyway
8831         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8832         next[0] = next[1] = true;
8833       }
8834       else {
8835         // insert
8836         // ------
8837         int intoBord = ( du < 0 ) ? 0 : 1;
8838         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8839         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8840         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8841         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8842         if ( intoBord == 1 ) {
8843           // move node of the border to be on a link of elem of the side
8844           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8845           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8846           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8847           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8848           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8849         }
8850         insertMapIt = insertMap.find( elem );
8851         bool notFound = ( insertMapIt == insertMap.end() );
8852         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8853         if ( otherLink ) {
8854           // insert into another link of the same element:
8855           // 1. perform insertion into the other link of the elem
8856           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8857           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8858           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8859           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8860           // 2. perform insertion into the link of adjacent faces
8861           while (true) {
8862             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8863             if ( adjElem )
8864               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8865             else
8866               break;
8867           }
8868           if (toCreatePolyedrs) {
8869             // perform insertion into the links of adjacent volumes
8870             UpdateVolumes(n12, n22, nodeList);
8871           }
8872           // 3. find an element appeared on n1 and n2 after the insertion
8873           insertMap.erase( elem );
8874           elem = findAdjacentFace( n1, n2, 0 );
8875         }
8876         if ( notFound || otherLink ) {
8877           // add element and nodes of the side into the insertMap
8878           insertMapIt = insertMap.insert
8879             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8880           (*insertMapIt).second.push_back( n1 );
8881           (*insertMapIt).second.push_back( n2 );
8882         }
8883         // add node to be inserted into elem
8884         (*insertMapIt).second.push_back( nIns );
8885         next[ 1 - intoBord ] = true;
8886       }
8887
8888       // go to the next segment
8889       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8890         if ( next[ iBord ] ) {
8891           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8892             eIt[ iBord ]++;
8893           nPrev[ iBord ] = *nIt[ iBord ];
8894           nIt[ iBord ]++; i[ iBord ]++;
8895         }
8896       }
8897     }
8898     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8899
8900     // perform insertion of nodes into elements
8901
8902     for (insertMapIt = insertMap.begin();
8903          insertMapIt != insertMap.end();
8904          insertMapIt++ )
8905     {
8906       const SMDS_MeshElement* elem = (*insertMapIt).first;
8907       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8908       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8909       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8910
8911       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8912
8913       if ( !theSideIsFreeBorder ) {
8914         // look for and insert nodes into the faces adjacent to elem
8915         while (true) {
8916           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8917           if ( adjElem )
8918             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8919           else
8920             break;
8921         }
8922       }
8923       if (toCreatePolyedrs) {
8924         // perform insertion into the links of adjacent volumes
8925         UpdateVolumes(n1, n2, nodeList);
8926       }
8927     }
8928
8929     delete param[0];
8930     delete param[1];
8931   } // end: insert new nodes
8932
8933   MergeNodes ( nodeGroupsToMerge );
8934
8935   return aResult;
8936 }
8937
8938 //=======================================================================
8939 //function : InsertNodesIntoLink
8940 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8941 //           and theBetweenNode2 and split theElement
8942 //=======================================================================
8943
8944 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8945                                            const SMDS_MeshNode*        theBetweenNode1,
8946                                            const SMDS_MeshNode*        theBetweenNode2,
8947                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8948                                            const bool                  toCreatePoly)
8949 {
8950   if ( theFace->GetType() != SMDSAbs_Face ) return;
8951
8952   // find indices of 2 link nodes and of the rest nodes
8953   int iNode = 0, il1, il2, i3, i4;
8954   il1 = il2 = i3 = i4 = -1;
8955   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8956   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8957
8958   if(theFace->IsQuadratic()) {
8959     const SMDS_VtkFace* F =
8960       dynamic_cast<const SMDS_VtkFace*>(theFace);
8961     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8962     // use special nodes iterator
8963     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8964     while( anIter->more() ) {
8965       const SMDS_MeshNode* n = cast2Node(anIter->next());
8966       if ( n == theBetweenNode1 )
8967         il1 = iNode;
8968       else if ( n == theBetweenNode2 )
8969         il2 = iNode;
8970       else if ( i3 < 0 )
8971         i3 = iNode;
8972       else
8973         i4 = iNode;
8974       nodes[ iNode++ ] = n;
8975     }
8976   }
8977   else {
8978     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8979     while ( nodeIt->more() ) {
8980       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8981       if ( n == theBetweenNode1 )
8982         il1 = iNode;
8983       else if ( n == theBetweenNode2 )
8984         il2 = iNode;
8985       else if ( i3 < 0 )
8986         i3 = iNode;
8987       else
8988         i4 = iNode;
8989       nodes[ iNode++ ] = n;
8990     }
8991   }
8992   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8993     return ;
8994
8995   // arrange link nodes to go one after another regarding the face orientation
8996   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8997   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8998   if ( reverse ) {
8999     iNode = il1;
9000     il1 = il2;
9001     il2 = iNode;
9002     aNodesToInsert.reverse();
9003   }
9004   // check that not link nodes of a quadrangles are in good order
9005   int nbFaceNodes = theFace->NbNodes();
9006   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
9007     iNode = i3;
9008     i3 = i4;
9009     i4 = iNode;
9010   }
9011
9012   if (toCreatePoly || theFace->IsPoly()) {
9013
9014     iNode = 0;
9015     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
9016
9017     // add nodes of face up to first node of link
9018     bool isFLN = false;
9019
9020     if(theFace->IsQuadratic()) {
9021       const SMDS_VtkFace* F =
9022         dynamic_cast<const SMDS_VtkFace*>(theFace);
9023       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9024       // use special nodes iterator
9025       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9026       while( anIter->more()  && !isFLN ) {
9027         const SMDS_MeshNode* n = cast2Node(anIter->next());
9028         poly_nodes[iNode++] = n;
9029         if (n == nodes[il1]) {
9030           isFLN = true;
9031         }
9032       }
9033       // add nodes to insert
9034       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9035       for (; nIt != aNodesToInsert.end(); nIt++) {
9036         poly_nodes[iNode++] = *nIt;
9037       }
9038       // add nodes of face starting from last node of link
9039       while ( anIter->more() ) {
9040         poly_nodes[iNode++] = cast2Node(anIter->next());
9041       }
9042     }
9043     else {
9044       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
9045       while ( nodeIt->more() && !isFLN ) {
9046         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9047         poly_nodes[iNode++] = n;
9048         if (n == nodes[il1]) {
9049           isFLN = true;
9050         }
9051       }
9052       // add nodes to insert
9053       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9054       for (; nIt != aNodesToInsert.end(); nIt++) {
9055         poly_nodes[iNode++] = *nIt;
9056       }
9057       // add nodes of face starting from last node of link
9058       while ( nodeIt->more() ) {
9059         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9060         poly_nodes[iNode++] = n;
9061       }
9062     }
9063
9064     // edit or replace the face
9065     SMESHDS_Mesh *aMesh = GetMeshDS();
9066
9067     if (theFace->IsPoly()) {
9068       aMesh->ChangePolygonNodes(theFace, poly_nodes);
9069     }
9070     else {
9071       int aShapeId = FindShape( theFace );
9072
9073       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
9074       myLastCreatedElems.Append(newElem);
9075       if ( aShapeId && newElem )
9076         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9077
9078       aMesh->RemoveElement(theFace);
9079     }
9080     return;
9081   }
9082
9083   SMESHDS_Mesh *aMesh = GetMeshDS();
9084   if( !theFace->IsQuadratic() ) {
9085
9086     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
9087     int nbLinkNodes = 2 + aNodesToInsert.size();
9088     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
9089     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
9090     linkNodes[ 0 ] = nodes[ il1 ];
9091     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
9092     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9093     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9094       linkNodes[ iNode++ ] = *nIt;
9095     }
9096     // decide how to split a quadrangle: compare possible variants
9097     // and choose which of splits to be a quadrangle
9098     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
9099     if ( nbFaceNodes == 3 ) {
9100       iBestQuad = nbSplits;
9101       i4 = i3;
9102     }
9103     else if ( nbFaceNodes == 4 ) {
9104       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
9105       double aBestRate = DBL_MAX;
9106       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
9107         i1 = 0; i2 = 1;
9108         double aBadRate = 0;
9109         // evaluate elements quality
9110         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
9111           if ( iSplit == iQuad ) {
9112             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
9113                                    linkNodes[ i2++ ],
9114                                    nodes[ i3 ],
9115                                    nodes[ i4 ]);
9116             aBadRate += getBadRate( &quad, aCrit );
9117           }
9118           else {
9119             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
9120                                    linkNodes[ i2++ ],
9121                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
9122             aBadRate += getBadRate( &tria, aCrit );
9123           }
9124         }
9125         // choice
9126         if ( aBadRate < aBestRate ) {
9127           iBestQuad = iQuad;
9128           aBestRate = aBadRate;
9129         }
9130       }
9131     }
9132
9133     // create new elements
9134     int aShapeId = FindShape( theFace );
9135
9136     i1 = 0; i2 = 1;
9137     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
9138       SMDS_MeshElement* newElem = 0;
9139       if ( iSplit == iBestQuad )
9140         newElem = aMesh->AddFace (linkNodes[ i1++ ],
9141                                   linkNodes[ i2++ ],
9142                                   nodes[ i3 ],
9143                                   nodes[ i4 ]);
9144       else
9145         newElem = aMesh->AddFace (linkNodes[ i1++ ],
9146                                   linkNodes[ i2++ ],
9147                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
9148       myLastCreatedElems.Append(newElem);
9149       if ( aShapeId && newElem )
9150         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9151     }
9152
9153     // change nodes of theFace
9154     const SMDS_MeshNode* newNodes[ 4 ];
9155     newNodes[ 0 ] = linkNodes[ i1 ];
9156     newNodes[ 1 ] = linkNodes[ i2 ];
9157     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
9158     newNodes[ 3 ] = nodes[ i4 ];
9159     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
9160     const SMDS_MeshElement* newElem = 0;
9161     if (iSplit == iBestQuad)
9162       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
9163     else
9164       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
9165     myLastCreatedElems.Append(newElem);
9166     if ( aShapeId && newElem )
9167       aMesh->SetMeshElementOnShape( newElem, aShapeId );
9168 } // end if(!theFace->IsQuadratic())
9169   else { // theFace is quadratic
9170     // we have to split theFace on simple triangles and one simple quadrangle
9171     int tmp = il1/2;
9172     int nbshift = tmp*2;
9173     // shift nodes in nodes[] by nbshift
9174     int i,j;
9175     for(i=0; i<nbshift; i++) {
9176       const SMDS_MeshNode* n = nodes[0];
9177       for(j=0; j<nbFaceNodes-1; j++) {
9178         nodes[j] = nodes[j+1];
9179       }
9180       nodes[nbFaceNodes-1] = n;
9181     }
9182     il1 = il1 - nbshift;
9183     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9184     //   n0      n1     n2    n0      n1     n2
9185     //     +-----+-----+        +-----+-----+
9186     //      \         /         |           |
9187     //       \       /          |           |
9188     //      n5+     +n3       n7+           +n3
9189     //         \   /            |           |
9190     //          \ /             |           |
9191     //           +              +-----+-----+
9192     //           n4           n6      n5     n4
9193
9194     // create new elements
9195     int aShapeId = FindShape( theFace );
9196
9197     int n1,n2,n3;
9198     if(nbFaceNodes==6) { // quadratic triangle
9199       SMDS_MeshElement* newElem =
9200         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9201       myLastCreatedElems.Append(newElem);
9202       if ( aShapeId && newElem )
9203         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9204       if(theFace->IsMediumNode(nodes[il1])) {
9205         // create quadrangle
9206         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9207         myLastCreatedElems.Append(newElem);
9208         if ( aShapeId && newElem )
9209           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9210         n1 = 1;
9211         n2 = 2;
9212         n3 = 3;
9213       }
9214       else {
9215         // create quadrangle
9216         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9217         myLastCreatedElems.Append(newElem);
9218         if ( aShapeId && newElem )
9219           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9220         n1 = 0;
9221         n2 = 1;
9222         n3 = 5;
9223       }
9224     }
9225     else { // nbFaceNodes==8 - quadratic quadrangle
9226       SMDS_MeshElement* newElem =
9227         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9228       myLastCreatedElems.Append(newElem);
9229       if ( aShapeId && newElem )
9230         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9231       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9232       myLastCreatedElems.Append(newElem);
9233       if ( aShapeId && newElem )
9234         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9235       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9236       myLastCreatedElems.Append(newElem);
9237       if ( aShapeId && newElem )
9238         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9239       if(theFace->IsMediumNode(nodes[il1])) {
9240         // create quadrangle
9241         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9242         myLastCreatedElems.Append(newElem);
9243         if ( aShapeId && newElem )
9244           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9245         n1 = 1;
9246         n2 = 2;
9247         n3 = 3;
9248       }
9249       else {
9250         // create quadrangle
9251         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9252         myLastCreatedElems.Append(newElem);
9253         if ( aShapeId && newElem )
9254           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9255         n1 = 0;
9256         n2 = 1;
9257         n3 = 7;
9258       }
9259     }
9260     // create needed triangles using n1,n2,n3 and inserted nodes
9261     int nbn = 2 + aNodesToInsert.size();
9262     //const SMDS_MeshNode* aNodes[nbn];
9263     vector<const SMDS_MeshNode*> aNodes(nbn);
9264     aNodes[0] = nodes[n1];
9265     aNodes[nbn-1] = nodes[n2];
9266     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9267     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9268       aNodes[iNode++] = *nIt;
9269     }
9270     for(i=1; i<nbn; i++) {
9271       SMDS_MeshElement* newElem =
9272         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9273       myLastCreatedElems.Append(newElem);
9274       if ( aShapeId && newElem )
9275         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9276     }
9277   }
9278   // remove old face
9279   aMesh->RemoveElement(theFace);
9280 }
9281
9282 //=======================================================================
9283 //function : UpdateVolumes
9284 //purpose  :
9285 //=======================================================================
9286 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9287                                       const SMDS_MeshNode*        theBetweenNode2,
9288                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9289 {
9290   myLastCreatedElems.Clear();
9291   myLastCreatedNodes.Clear();
9292
9293   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9294   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9295     const SMDS_MeshElement* elem = invElemIt->next();
9296
9297     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9298     SMDS_VolumeTool aVolume (elem);
9299     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9300       continue;
9301
9302     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9303     int iface, nbFaces = aVolume.NbFaces();
9304     vector<const SMDS_MeshNode *> poly_nodes;
9305     vector<int> quantities (nbFaces);
9306
9307     for (iface = 0; iface < nbFaces; iface++) {
9308       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9309       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9310       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9311
9312       for (int inode = 0; inode < nbFaceNodes; inode++) {
9313         poly_nodes.push_back(faceNodes[inode]);
9314
9315         if (nbInserted == 0) {
9316           if (faceNodes[inode] == theBetweenNode1) {
9317             if (faceNodes[inode + 1] == theBetweenNode2) {
9318               nbInserted = theNodesToInsert.size();
9319
9320               // add nodes to insert
9321               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9322               for (; nIt != theNodesToInsert.end(); nIt++) {
9323                 poly_nodes.push_back(*nIt);
9324               }
9325             }
9326           }
9327           else if (faceNodes[inode] == theBetweenNode2) {
9328             if (faceNodes[inode + 1] == theBetweenNode1) {
9329               nbInserted = theNodesToInsert.size();
9330
9331               // add nodes to insert in reversed order
9332               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9333               nIt--;
9334               for (; nIt != theNodesToInsert.begin(); nIt--) {
9335                 poly_nodes.push_back(*nIt);
9336               }
9337               poly_nodes.push_back(*nIt);
9338             }
9339           }
9340           else {
9341           }
9342         }
9343       }
9344       quantities[iface] = nbFaceNodes + nbInserted;
9345     }
9346
9347     // Replace or update the volume
9348     SMESHDS_Mesh *aMesh = GetMeshDS();
9349
9350     if (elem->IsPoly()) {
9351       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9352
9353     }
9354     else {
9355       int aShapeId = FindShape( elem );
9356
9357       SMDS_MeshElement* newElem =
9358         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9359       myLastCreatedElems.Append(newElem);
9360       if (aShapeId && newElem)
9361         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9362
9363       aMesh->RemoveElement(elem);
9364     }
9365   }
9366 }
9367
9368 namespace
9369 {
9370   //================================================================================
9371   /*!
9372    * \brief Transform any volume into data of SMDSEntity_Polyhedra
9373    */
9374   //================================================================================
9375
9376   void volumeToPolyhedron( const SMDS_MeshElement*         elem,
9377                            vector<const SMDS_MeshNode *> & nodes,
9378                            vector<int> &                   nbNodeInFaces )
9379   {
9380     nodes.clear();
9381     nbNodeInFaces.clear();
9382     SMDS_VolumeTool vTool ( elem );
9383     for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
9384     {
9385       const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
9386       nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
9387       nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
9388     }
9389   }
9390 }
9391
9392 //=======================================================================
9393 /*!
9394  * \brief Convert elements contained in a submesh to quadratic
9395  * \return int - nb of checked elements
9396  */
9397 //=======================================================================
9398
9399 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9400                                              SMESH_MesherHelper& theHelper,
9401                                              const bool          theForce3d)
9402 {
9403   int nbElem = 0;
9404   if( !theSm ) return nbElem;
9405
9406   vector<int> nbNodeInFaces;
9407   vector<const SMDS_MeshNode *> nodes;
9408   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9409   while(ElemItr->more())
9410   {
9411     nbElem++;
9412     const SMDS_MeshElement* elem = ElemItr->next();
9413     if( !elem || elem->IsQuadratic() ) continue;
9414
9415     // get elem data needed to re-create it
9416     //
9417     const int id                        = elem->GetID();
9418     const int nbNodes                   = elem->NbNodes();
9419     const SMDSAbs_ElementType aType     = elem->GetType();
9420     const SMDSAbs_EntityType  aGeomType = elem->GetEntityType();
9421     nodes.assign(elem->begin_nodes(), elem->end_nodes());
9422     if ( aGeomType == SMDSEntity_Polyhedra )
9423       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9424     else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
9425       volumeToPolyhedron( elem, nodes, nbNodeInFaces );
9426
9427     // remove a linear element
9428     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9429
9430     const SMDS_MeshElement* NewElem = 0;
9431
9432     switch( aType )
9433     {
9434     case SMDSAbs_Edge :
9435       {
9436         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9437         break;
9438       }
9439     case SMDSAbs_Face :
9440       {
9441         switch(nbNodes)
9442         {
9443         case 3:
9444           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9445           break;
9446         case 4:
9447           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9448           break;
9449         default:
9450           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9451           continue;
9452         }
9453         break;
9454       }
9455     case SMDSAbs_Volume :
9456       {
9457         switch( aGeomType )
9458         {
9459         case SMDSEntity_Tetra:
9460           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9461           break;
9462         case SMDSEntity_Pyramid:
9463           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9464           break;
9465         case SMDSEntity_Penta:
9466           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9467           break;
9468         case SMDSEntity_Hexa:
9469           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9470                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9471           break;
9472         case SMDSEntity_Hexagonal_Prism:
9473         default:
9474           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9475         }
9476         break;
9477       }
9478     default :
9479       continue;
9480     }
9481     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9482     if( NewElem )
9483       theSm->AddElement( NewElem );
9484   }
9485   return nbElem;
9486 }
9487
9488 //=======================================================================
9489 //function : ConvertToQuadratic
9490 //purpose  :
9491 //=======================================================================
9492
9493 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9494 {
9495   SMESHDS_Mesh* meshDS = GetMeshDS();
9496
9497   SMESH_MesherHelper aHelper(*myMesh);
9498   aHelper.SetIsQuadratic( true );
9499
9500   int nbCheckedElems = 0;
9501   if ( myMesh->HasShapeToMesh() )
9502   {
9503     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9504     {
9505       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9506       while ( smIt->more() ) {
9507         SMESH_subMesh* sm = smIt->next();
9508         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9509           aHelper.SetSubShape( sm->GetSubShape() );
9510           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9511         }
9512       }
9513     }
9514   }
9515   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9516   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9517   {
9518     SMESHDS_SubMesh *smDS = 0;
9519     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9520     while(aEdgeItr->more())
9521     {
9522       const SMDS_MeshEdge* edge = aEdgeItr->next();
9523       if(edge && !edge->IsQuadratic())
9524       {
9525         int id = edge->GetID();
9526         //MESSAGE("edge->GetID() " << id);
9527         const SMDS_MeshNode* n1 = edge->GetNode(0);
9528         const SMDS_MeshNode* n2 = edge->GetNode(1);
9529
9530         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9531
9532         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9533         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9534       }
9535     }
9536     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9537     while(aFaceItr->more())
9538     {
9539       const SMDS_MeshFace* face = aFaceItr->next();
9540       if(!face || face->IsQuadratic() ) continue;
9541
9542       const int id = face->GetID();
9543       const SMDSAbs_EntityType type = face->GetEntityType();
9544       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9545
9546       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9547
9548       SMDS_MeshFace * NewFace = 0;
9549       switch( type )
9550       {
9551       case SMDSEntity_Triangle:
9552         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9553         break;
9554       case SMDSEntity_Quadrangle:
9555         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9556         break;
9557       default:
9558         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9559       }
9560       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9561     }
9562     vector<int> nbNodeInFaces;
9563     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9564     while(aVolumeItr->more())
9565     {
9566       const SMDS_MeshVolume* volume = aVolumeItr->next();
9567       if(!volume || volume->IsQuadratic() ) continue;
9568
9569       const int id = volume->GetID();
9570       const SMDSAbs_EntityType type = volume->GetEntityType();
9571       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9572       if ( type == SMDSEntity_Polyhedra )
9573         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9574       else if ( type == SMDSEntity_Hexagonal_Prism )
9575         volumeToPolyhedron( volume, nodes, nbNodeInFaces );
9576
9577       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9578
9579       SMDS_MeshVolume * NewVolume = 0;
9580       switch ( type )
9581       {
9582       case SMDSEntity_Tetra:
9583         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
9584         break;
9585       case SMDSEntity_Hexa:
9586         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9587                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9588         break;
9589       case SMDSEntity_Pyramid:
9590         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9591                                       nodes[3], nodes[4], id, theForce3d);
9592         break;
9593       case SMDSEntity_Penta:
9594         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9595                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9596         break;
9597       case SMDSEntity_Hexagonal_Prism:
9598       default:
9599         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9600       }
9601       ReplaceElemInGroups(volume, NewVolume, meshDS);
9602     }
9603   }
9604
9605   if ( !theForce3d )
9606   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9607     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9608     aHelper.FixQuadraticElements();
9609   }
9610 }
9611
9612 //================================================================================
9613 /*!
9614  * \brief Makes given elements quadratic
9615  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9616  *  \param theElements - elements to make quadratic 
9617  */
9618 //================================================================================
9619
9620 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9621                                           TIDSortedElemSet& theElements)
9622 {
9623   if ( theElements.empty() ) return;
9624
9625   // we believe that all theElements are of the same type
9626   const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9627   
9628   // get all nodes shared by theElements
9629   TIDSortedNodeSet allNodes;
9630   TIDSortedElemSet::iterator eIt = theElements.begin();
9631   for ( ; eIt != theElements.end(); ++eIt )
9632     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9633
9634   // complete theElements with elements of lower dim whose all nodes are in allNodes
9635
9636   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9637   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9638   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9639   for ( ; nIt != allNodes.end(); ++nIt )
9640   {
9641     const SMDS_MeshNode* n = *nIt;
9642     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9643     while ( invIt->more() )
9644     {
9645       const SMDS_MeshElement* e = invIt->next();
9646       if ( e->IsQuadratic() )
9647       {
9648         quadAdjacentElems[ e->GetType() ].insert( e );
9649         continue;
9650       }
9651       if ( e->GetType() >= elemType )
9652       {
9653         continue; // same type of more complex linear element
9654       }
9655
9656       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9657         continue; // e is already checked
9658
9659       // check nodes
9660       bool allIn = true;
9661       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9662       while ( nodeIt->more() && allIn )
9663         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9664       if ( allIn )
9665         theElements.insert(e );
9666     }
9667   }
9668
9669   SMESH_MesherHelper helper(*myMesh);
9670   helper.SetIsQuadratic( true );
9671
9672   // add links of quadratic adjacent elements to the helper
9673
9674   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9675     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9676           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9677     {
9678       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9679     }
9680   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9681     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9682           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9683     {
9684       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9685     }
9686   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9687     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9688           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9689     {
9690       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9691     }
9692
9693   // make quadratic elements instead of linear ones
9694
9695   SMESHDS_Mesh* meshDS = GetMeshDS();
9696   SMESHDS_SubMesh* smDS = 0;
9697   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9698   {
9699     const SMDS_MeshElement* elem = *eIt;
9700     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9701       continue;
9702
9703     const int id                   = elem->GetID();
9704     const SMDSAbs_ElementType type = elem->GetType();
9705     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9706
9707     if ( !smDS || !smDS->Contains( elem ))
9708       smDS = meshDS->MeshElements( elem->getshapeId() );
9709     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9710
9711     SMDS_MeshElement * newElem = 0;
9712     switch( nodes.size() )
9713     {
9714     case 4: // cases for most frequently used element types go first (for optimization)
9715       if ( type == SMDSAbs_Volume )
9716         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9717       else
9718         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9719       break;
9720     case 8:
9721       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9722                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9723       break;
9724     case 3:
9725       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9726       break;
9727     case 2:
9728       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9729       break;
9730     case 5:
9731       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9732                                  nodes[4], id, theForce3d);
9733       break;
9734     case 6:
9735       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9736                                  nodes[4], nodes[5], id, theForce3d);
9737       break;
9738     default:;
9739     }
9740     ReplaceElemInGroups( elem, newElem, meshDS);
9741     if( newElem && smDS )
9742       smDS->AddElement( newElem );
9743   }
9744
9745   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9746   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9747     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9748     helper.FixQuadraticElements();
9749   }
9750 }
9751
9752 //=======================================================================
9753 /*!
9754  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9755  * \return int - nb of checked elements
9756  */
9757 //=======================================================================
9758
9759 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9760                                      SMDS_ElemIteratorPtr theItr,
9761                                      const int            theShapeID)
9762 {
9763   int nbElem = 0;
9764   SMESHDS_Mesh* meshDS = GetMeshDS();
9765
9766   while( theItr->more() )
9767   {
9768     const SMDS_MeshElement* elem = theItr->next();
9769     nbElem++;
9770     if( elem && elem->IsQuadratic())
9771     {
9772       int id                    = elem->GetID();
9773       int nbCornerNodes         = elem->NbCornerNodes();
9774       SMDSAbs_ElementType aType = elem->GetType();
9775
9776       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9777
9778       //remove a quadratic element
9779       if ( !theSm || !theSm->Contains( elem ))
9780         theSm = meshDS->MeshElements( elem->getshapeId() );
9781       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9782
9783       // remove medium nodes
9784       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9785         if ( nodes[i]->NbInverseElements() == 0 )
9786           meshDS->RemoveFreeNode( nodes[i], theSm );
9787
9788       // add a linear element
9789       nodes.resize( nbCornerNodes );
9790       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9791       ReplaceElemInGroups(elem, newElem, meshDS);
9792       if( theSm && newElem )
9793         theSm->AddElement( newElem );
9794     }
9795   }
9796   return nbElem;
9797 }
9798
9799 //=======================================================================
9800 //function : ConvertFromQuadratic
9801 //purpose  :
9802 //=======================================================================
9803
9804 bool SMESH_MeshEditor::ConvertFromQuadratic()
9805 {
9806   int nbCheckedElems = 0;
9807   if ( myMesh->HasShapeToMesh() )
9808   {
9809     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9810     {
9811       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9812       while ( smIt->more() ) {
9813         SMESH_subMesh* sm = smIt->next();
9814         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9815           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9816       }
9817     }
9818   }
9819
9820   int totalNbElems =
9821     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9822   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9823   {
9824     SMESHDS_SubMesh *aSM = 0;
9825     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9826   }
9827
9828   return true;
9829 }
9830
9831 namespace
9832 {
9833   //================================================================================
9834   /*!
9835    * \brief Return true if all medium nodes of the element are in the node set
9836    */
9837   //================================================================================
9838
9839   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9840   {
9841     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9842       if ( !nodeSet.count( elem->GetNode(i) ))
9843         return false;
9844     return true;
9845   }
9846 }
9847
9848 //================================================================================
9849 /*!
9850  * \brief Makes given elements linear
9851  */
9852 //================================================================================
9853
9854 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9855 {
9856   if ( theElements.empty() ) return;
9857
9858   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9859   set<int> mediumNodeIDs;
9860   TIDSortedElemSet::iterator eIt = theElements.begin();
9861   for ( ; eIt != theElements.end(); ++eIt )
9862   {
9863     const SMDS_MeshElement* e = *eIt;
9864     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9865       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9866   }
9867
9868   // replace given elements by linear ones
9869   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9870   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9871   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9872
9873   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9874   // except those elements sharing medium nodes of quadratic element whose medium nodes
9875   // are not all in mediumNodeIDs
9876
9877   // get remaining medium nodes
9878   TIDSortedNodeSet mediumNodes;
9879   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9880   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9881     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9882       mediumNodes.insert( mediumNodes.end(), n );
9883
9884   // find more quadratic elements to convert
9885   TIDSortedElemSet moreElemsToConvert;
9886   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9887   for ( ; nIt != mediumNodes.end(); ++nIt )
9888   {
9889     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9890     while ( invIt->more() )
9891     {
9892       const SMDS_MeshElement* e = invIt->next();
9893       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9894       {
9895         // find a more complex element including e and
9896         // whose medium nodes are not in mediumNodes
9897         bool complexFound = false;
9898         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9899         {
9900           SMDS_ElemIteratorPtr invIt2 =
9901             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9902           while ( invIt2->more() )
9903           {
9904             const SMDS_MeshElement* eComplex = invIt2->next();
9905             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9906             {
9907               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9908               if ( nbCommonNodes == e->NbNodes())
9909               {
9910                 complexFound = true;
9911                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9912                 break;
9913               }
9914             }
9915           }
9916         }
9917         if ( !complexFound )
9918           moreElemsToConvert.insert( e );
9919       }
9920     }
9921   }
9922   elemIt = SMDS_ElemIteratorPtr
9923     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9924   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9925 }
9926
9927 //=======================================================================
9928 //function : SewSideElements
9929 //purpose  :
9930 //=======================================================================
9931
9932 SMESH_MeshEditor::Sew_Error
9933 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9934                                    TIDSortedElemSet&    theSide2,
9935                                    const SMDS_MeshNode* theFirstNode1,
9936                                    const SMDS_MeshNode* theFirstNode2,
9937                                    const SMDS_MeshNode* theSecondNode1,
9938                                    const SMDS_MeshNode* theSecondNode2)
9939 {
9940   myLastCreatedElems.Clear();
9941   myLastCreatedNodes.Clear();
9942
9943   MESSAGE ("::::SewSideElements()");
9944   if ( theSide1.size() != theSide2.size() )
9945     return SEW_DIFF_NB_OF_ELEMENTS;
9946
9947   Sew_Error aResult = SEW_OK;
9948   // Algo:
9949   // 1. Build set of faces representing each side
9950   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9951   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9952
9953   // =======================================================================
9954   // 1. Build set of faces representing each side:
9955   // =======================================================================
9956   // a. build set of nodes belonging to faces
9957   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9958   // c. create temporary faces representing side of volumes if correspondent
9959   //    face does not exist
9960
9961   SMESHDS_Mesh* aMesh = GetMeshDS();
9962   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9963   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9964   TIDSortedElemSet             faceSet1, faceSet2;
9965   set<const SMDS_MeshElement*> volSet1,  volSet2;
9966   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9967   TIDSortedElemSet             * faceSetPtr[] = { &faceSet1, &faceSet2 };
9968   set<const SMDS_MeshElement*> *  volSetPtr[] = { &volSet1,  &volSet2  };
9969   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9970   TIDSortedElemSet             * elemSetPtr[] = { &theSide1, &theSide2 };
9971   int iSide, iFace, iNode;
9972
9973   list<const SMDS_MeshElement* > tempFaceList;
9974   for ( iSide = 0; iSide < 2; iSide++ ) {
9975     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9976     TIDSortedElemSet             * elemSet = elemSetPtr[ iSide ];
9977     TIDSortedElemSet             * faceSet = faceSetPtr[ iSide ];
9978     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9979     set<const SMDS_MeshElement*>::iterator vIt;
9980     TIDSortedElemSet::iterator eIt;
9981     set<const SMDS_MeshNode*>::iterator    nIt;
9982
9983     // check that given nodes belong to given elements
9984     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9985     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9986     int firstIndex = -1, secondIndex = -1;
9987     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9988       const SMDS_MeshElement* elem = *eIt;
9989       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9990       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9991       if ( firstIndex > -1 && secondIndex > -1 ) break;
9992     }
9993     if ( firstIndex < 0 || secondIndex < 0 ) {
9994       // we can simply return until temporary faces created
9995       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9996     }
9997
9998     // -----------------------------------------------------------
9999     // 1a. Collect nodes of existing faces
10000     //     and build set of face nodes in order to detect missing
10001     //     faces corresponding to sides of volumes
10002     // -----------------------------------------------------------
10003
10004     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
10005
10006     // loop on the given element of a side
10007     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
10008       //const SMDS_MeshElement* elem = *eIt;
10009       const SMDS_MeshElement* elem = *eIt;
10010       if ( elem->GetType() == SMDSAbs_Face ) {
10011         faceSet->insert( elem );
10012         set <const SMDS_MeshNode*> faceNodeSet;
10013         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
10014         while ( nodeIt->more() ) {
10015           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10016           nodeSet->insert( n );
10017           faceNodeSet.insert( n );
10018         }
10019         setOfFaceNodeSet.insert( faceNodeSet );
10020       }
10021       else if ( elem->GetType() == SMDSAbs_Volume )
10022         volSet->insert( elem );
10023     }
10024     // ------------------------------------------------------------------------------
10025     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
10026     // ------------------------------------------------------------------------------
10027
10028     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10029       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10030       while ( fIt->more() ) { // loop on faces sharing a node
10031         const SMDS_MeshElement* f = fIt->next();
10032         if ( faceSet->find( f ) == faceSet->end() ) {
10033           // check if all nodes are in nodeSet and
10034           // complete setOfFaceNodeSet if they are
10035           set <const SMDS_MeshNode*> faceNodeSet;
10036           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10037           bool allInSet = true;
10038           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10039             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10040             if ( nodeSet->find( n ) == nodeSet->end() )
10041               allInSet = false;
10042             else
10043               faceNodeSet.insert( n );
10044           }
10045           if ( allInSet ) {
10046             faceSet->insert( f );
10047             setOfFaceNodeSet.insert( faceNodeSet );
10048           }
10049         }
10050       }
10051     }
10052
10053     // -------------------------------------------------------------------------
10054     // 1c. Create temporary faces representing sides of volumes if correspondent
10055     //     face does not exist
10056     // -------------------------------------------------------------------------
10057
10058     if ( !volSet->empty() ) {
10059       //int nodeSetSize = nodeSet->size();
10060
10061       // loop on given volumes
10062       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
10063         SMDS_VolumeTool vol (*vIt);
10064         // loop on volume faces: find free faces
10065         // --------------------------------------
10066         list<const SMDS_MeshElement* > freeFaceList;
10067         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
10068           if ( !vol.IsFreeFace( iFace ))
10069             continue;
10070           // check if there is already a face with same nodes in a face set
10071           const SMDS_MeshElement* aFreeFace = 0;
10072           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
10073           int nbNodes = vol.NbFaceNodes( iFace );
10074           set <const SMDS_MeshNode*> faceNodeSet;
10075           vol.GetFaceNodes( iFace, faceNodeSet );
10076           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
10077           if ( isNewFace ) {
10078             // no such a face is given but it still can exist, check it
10079             vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
10080             aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
10081           }
10082           if ( !aFreeFace ) {
10083             // create a temporary face
10084             if ( nbNodes == 3 ) {
10085               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
10086               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
10087             }
10088             else if ( nbNodes == 4 ) {
10089               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10090               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10091             }
10092             else {
10093               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
10094               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
10095               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
10096             }
10097             if ( aFreeFace )
10098               tempFaceList.push_back( aFreeFace );
10099           }
10100
10101           if ( aFreeFace )
10102             freeFaceList.push_back( aFreeFace );
10103
10104         } // loop on faces of a volume
10105
10106         // choose one of several free faces of a volume
10107         // --------------------------------------------
10108         if ( freeFaceList.size() > 1 ) {
10109           // choose a face having max nb of nodes shared by other elems of a side
10110           int maxNbNodes = -1;
10111           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
10112           while ( fIt != freeFaceList.end() ) { // loop on free faces
10113             int nbSharedNodes = 0;
10114             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
10115             while ( nodeIt->more() ) { // loop on free face nodes
10116               const SMDS_MeshNode* n =
10117                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10118               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
10119               while ( invElemIt->more() ) {
10120                 const SMDS_MeshElement* e = invElemIt->next();
10121                 nbSharedNodes += faceSet->count( e );
10122                 nbSharedNodes += elemSet->count( e );
10123               }
10124             }
10125             if ( nbSharedNodes > maxNbNodes ) {
10126               maxNbNodes = nbSharedNodes;
10127               freeFaceList.erase( freeFaceList.begin(), fIt++ );
10128             }
10129             else if ( nbSharedNodes == maxNbNodes ) {
10130               fIt++;
10131             }
10132             else {
10133               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
10134             }
10135           }
10136           if ( freeFaceList.size() > 1 )
10137           {
10138             // could not choose one face, use another way
10139             // choose a face most close to the bary center of the opposite side
10140             gp_XYZ aBC( 0., 0., 0. );
10141             set <const SMDS_MeshNode*> addedNodes;
10142             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
10143             eIt = elemSet2->begin();
10144             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
10145               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
10146               while ( nodeIt->more() ) { // loop on free face nodes
10147                 const SMDS_MeshNode* n =
10148                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10149                 if ( addedNodes.insert( n ).second )
10150                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
10151               }
10152             }
10153             aBC /= addedNodes.size();
10154             double minDist = DBL_MAX;
10155             fIt = freeFaceList.begin();
10156             while ( fIt != freeFaceList.end() ) { // loop on free faces
10157               double dist = 0;
10158               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
10159               while ( nodeIt->more() ) { // loop on free face nodes
10160                 const SMDS_MeshNode* n =
10161                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10162                 gp_XYZ p( n->X(),n->Y(),n->Z() );
10163                 dist += ( aBC - p ).SquareModulus();
10164               }
10165               if ( dist < minDist ) {
10166                 minDist = dist;
10167                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
10168               }
10169               else
10170                 fIt = freeFaceList.erase( fIt++ );
10171             }
10172           }
10173         } // choose one of several free faces of a volume
10174
10175         if ( freeFaceList.size() == 1 ) {
10176           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
10177           faceSet->insert( aFreeFace );
10178           // complete a node set with nodes of a found free face
10179           //           for ( iNode = 0; iNode < ; iNode++ )
10180           //             nodeSet->insert( fNodes[ iNode ] );
10181         }
10182
10183       } // loop on volumes of a side
10184
10185       //       // complete a set of faces if new nodes in a nodeSet appeared
10186       //       // ----------------------------------------------------------
10187       //       if ( nodeSetSize != nodeSet->size() ) {
10188       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10189       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10190       //           while ( fIt->more() ) { // loop on faces sharing a node
10191       //             const SMDS_MeshElement* f = fIt->next();
10192       //             if ( faceSet->find( f ) == faceSet->end() ) {
10193       //               // check if all nodes are in nodeSet and
10194       //               // complete setOfFaceNodeSet if they are
10195       //               set <const SMDS_MeshNode*> faceNodeSet;
10196       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10197       //               bool allInSet = true;
10198       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10199       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10200       //                 if ( nodeSet->find( n ) == nodeSet->end() )
10201       //                   allInSet = false;
10202       //                 else
10203       //                   faceNodeSet.insert( n );
10204       //               }
10205       //               if ( allInSet ) {
10206       //                 faceSet->insert( f );
10207       //                 setOfFaceNodeSet.insert( faceNodeSet );
10208       //               }
10209       //             }
10210       //           }
10211       //         }
10212       //       }
10213     } // Create temporary faces, if there are volumes given
10214   } // loop on sides
10215
10216   if ( faceSet1.size() != faceSet2.size() ) {
10217     // delete temporary faces: they are in reverseElements of actual nodes
10218 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10219 //    while ( tmpFaceIt->more() )
10220 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10221 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10222 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10223 //      aMesh->RemoveElement(*tmpFaceIt);
10224     MESSAGE("Diff nb of faces");
10225     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10226   }
10227
10228   // ============================================================
10229   // 2. Find nodes to merge:
10230   //              bind a node to remove to a node to put instead
10231   // ============================================================
10232
10233   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10234   if ( theFirstNode1 != theFirstNode2 )
10235     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10236   if ( theSecondNode1 != theSecondNode2 )
10237     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10238
10239   LinkID_Gen aLinkID_Gen( GetMeshDS() );
10240   set< long > linkIdSet; // links to process
10241   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10242
10243   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10244   list< NLink > linkList[2];
10245   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10246   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10247   // loop on links in linkList; find faces by links and append links
10248   // of the found faces to linkList
10249   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10250   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
10251   {
10252     NLink link[] = { *linkIt[0], *linkIt[1] };
10253     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10254     if ( !linkIdSet.count( linkID ) )
10255       continue;
10256
10257     // by links, find faces in the face sets,
10258     // and find indices of link nodes in the found faces;
10259     // in a face set, there is only one or no face sharing a link
10260     // ---------------------------------------------------------------
10261
10262     const SMDS_MeshElement* face[] = { 0, 0 };
10263     vector<const SMDS_MeshNode*> fnodes[2];
10264     int iLinkNode[2][2];
10265     TIDSortedElemSet avoidSet;
10266     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10267       const SMDS_MeshNode* n1 = link[iSide].first;
10268       const SMDS_MeshNode* n2 = link[iSide].second;
10269       //cout << "Side " << iSide << " ";
10270       //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
10271       // find a face by two link nodes
10272       face[ iSide ] = FindFaceInSet( n1, n2, *faceSetPtr[ iSide ], avoidSet,
10273                                      &iLinkNode[iSide][0], &iLinkNode[iSide][1] );
10274       if ( face[ iSide ])
10275       {
10276         //cout << " F " << face[ iSide]->GetID() <<endl;
10277         faceSetPtr[ iSide ]->erase( face[ iSide ]);
10278         // put face nodes to fnodes
10279         if ( face[ iSide ]->IsQuadratic() )
10280         {
10281           // use interlaced nodes iterator
10282           const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
10283           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10284           SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
10285           while ( nIter->more() )
10286             fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
10287         }
10288         else
10289         {
10290           fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
10291                                   face[ iSide ]->end_nodes() );
10292         }
10293         fnodes[ iSide ].push_back( fnodes[ iSide ].front());
10294       }
10295     }
10296
10297     // check similarity of elements of the sides
10298     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10299       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10300       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10301         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10302       }
10303       else {
10304         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10305       }
10306       break; // do not return because it's necessary to remove tmp faces
10307     }
10308
10309     // set nodes to merge
10310     // -------------------
10311
10312     if ( face[0] && face[1] )  {
10313       const int nbNodes = face[0]->NbNodes();
10314       if ( nbNodes != face[1]->NbNodes() ) {
10315         MESSAGE("Diff nb of face nodes");
10316         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10317         break; // do not return because it s necessary to remove tmp faces
10318       }
10319       bool reverse[] = { false, false }; // order of nodes in the link
10320       for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10321         // analyse link orientation in faces
10322         int i1 = iLinkNode[ iSide ][ 0 ];
10323         int i2 = iLinkNode[ iSide ][ 1 ];
10324         reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10325       }
10326       int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
10327       int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
10328       for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
10329       {
10330         nReplaceMap.insert  ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
10331                                           fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
10332       }
10333
10334       // add other links of the faces to linkList
10335       // -----------------------------------------
10336
10337       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10338         linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
10339         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10340         if ( !iter_isnew.second ) { // already in a set: no need to process
10341           linkIdSet.erase( iter_isnew.first );
10342         }
10343         else // new in set == encountered for the first time: add
10344         {
10345           const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
10346           const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
10347           linkList[0].push_back ( NLink( n1, n2 ));
10348           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10349         }
10350       }
10351     } // 2 faces found
10352
10353     if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
10354       break;
10355
10356   } // loop on link lists
10357
10358   if ( aResult == SEW_OK &&
10359        ( //linkIt[0] != linkList[0].end() ||
10360          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10361     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10362              " " << (faceSetPtr[1]->empty()));
10363     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10364   }
10365
10366   // ====================================================================
10367   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10368   // ====================================================================
10369
10370   // delete temporary faces
10371 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10372 //  while ( tmpFaceIt->more() )
10373 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10374   list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10375   for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10376     aMesh->RemoveElement(*tmpFaceIt);
10377
10378   if ( aResult != SEW_OK)
10379     return aResult;
10380
10381   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10382   // loop on nodes replacement map
10383   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10384   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10385     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10386       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10387       nodeIDsToRemove.push_back( nToRemove->GetID() );
10388       // loop on elements sharing nToRemove
10389       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10390       while ( invElemIt->more() ) {
10391         const SMDS_MeshElement* e = invElemIt->next();
10392         // get a new suite of nodes: make replacement
10393         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10394         vector< const SMDS_MeshNode*> nodes( nbNodes );
10395         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10396         while ( nIt->more() ) {
10397           const SMDS_MeshNode* n =
10398             static_cast<const SMDS_MeshNode*>( nIt->next() );
10399           nnIt = nReplaceMap.find( n );
10400           if ( nnIt != nReplaceMap.end() ) {
10401             nbReplaced++;
10402             n = (*nnIt).second;
10403           }
10404           nodes[ i++ ] = n;
10405         }
10406         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10407         //         elemIDsToRemove.push_back( e->GetID() );
10408         //       else
10409         if ( nbReplaced )
10410           {
10411             SMDSAbs_ElementType etyp = e->GetType();
10412             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10413             if (newElem)
10414               {
10415                 myLastCreatedElems.Append(newElem);
10416                 AddToSameGroups(newElem, e, aMesh);
10417                 int aShapeId = e->getshapeId();
10418                 if ( aShapeId )
10419                   {
10420                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10421                   }
10422               }
10423             aMesh->RemoveElement(e);
10424           }
10425       }
10426     }
10427
10428   Remove( nodeIDsToRemove, true );
10429
10430   return aResult;
10431 }
10432
10433 //================================================================================
10434 /*!
10435  * \brief Find corresponding nodes in two sets of faces
10436  * \param theSide1 - first face set
10437  * \param theSide2 - second first face
10438  * \param theFirstNode1 - a boundary node of set 1
10439  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10440  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10441  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10442  * \param nReplaceMap - output map of corresponding nodes
10443  * \return bool  - is a success or not
10444  */
10445 //================================================================================
10446
10447 #ifdef _DEBUG_
10448 //#define DEBUG_MATCHING_NODES
10449 #endif
10450
10451 SMESH_MeshEditor::Sew_Error
10452 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10453                                     set<const SMDS_MeshElement*>& theSide2,
10454                                     const SMDS_MeshNode*          theFirstNode1,
10455                                     const SMDS_MeshNode*          theFirstNode2,
10456                                     const SMDS_MeshNode*          theSecondNode1,
10457                                     const SMDS_MeshNode*          theSecondNode2,
10458                                     TNodeNodeMap &                nReplaceMap)
10459 {
10460   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10461
10462   nReplaceMap.clear();
10463   if ( theFirstNode1 != theFirstNode2 )
10464     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10465   if ( theSecondNode1 != theSecondNode2 )
10466     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10467
10468   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10469   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10470
10471   list< NLink > linkList[2];
10472   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10473   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10474
10475   // loop on links in linkList; find faces by links and append links
10476   // of the found faces to linkList
10477   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10478   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10479     NLink link[] = { *linkIt[0], *linkIt[1] };
10480     if ( linkSet.find( link[0] ) == linkSet.end() )
10481       continue;
10482
10483     // by links, find faces in the face sets,
10484     // and find indices of link nodes in the found faces;
10485     // in a face set, there is only one or no face sharing a link
10486     // ---------------------------------------------------------------
10487
10488     const SMDS_MeshElement* face[] = { 0, 0 };
10489     list<const SMDS_MeshNode*> notLinkNodes[2];
10490     //bool reverse[] = { false, false }; // order of notLinkNodes
10491     int nbNodes[2];
10492     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10493     {
10494       const SMDS_MeshNode* n1 = link[iSide].first;
10495       const SMDS_MeshNode* n2 = link[iSide].second;
10496       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10497       set< const SMDS_MeshElement* > facesOfNode1;
10498       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10499       {
10500         // during a loop of the first node, we find all faces around n1,
10501         // during a loop of the second node, we find one face sharing both n1 and n2
10502         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10503         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10504         while ( fIt->more() ) { // loop on faces sharing a node
10505           const SMDS_MeshElement* f = fIt->next();
10506           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10507               ! facesOfNode1.insert( f ).second ) // f encounters twice
10508           {
10509             if ( face[ iSide ] ) {
10510               MESSAGE( "2 faces per link " );
10511               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10512             }
10513             face[ iSide ] = f;
10514             faceSet->erase( f );
10515
10516             // get not link nodes
10517             int nbN = f->NbNodes();
10518             if ( f->IsQuadratic() )
10519               nbN /= 2;
10520             nbNodes[ iSide ] = nbN;
10521             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10522             int i1 = f->GetNodeIndex( n1 );
10523             int i2 = f->GetNodeIndex( n2 );
10524             int iEnd = nbN, iBeg = -1, iDelta = 1;
10525             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10526             if ( reverse ) {
10527               std::swap( iEnd, iBeg ); iDelta = -1;
10528             }
10529             int i = i2;
10530             while ( true ) {
10531               i += iDelta;
10532               if ( i == iEnd ) i = iBeg + iDelta;
10533               if ( i == i1 ) break;
10534               nodes.push_back ( f->GetNode( i ) );
10535             }
10536           }
10537         }
10538       }
10539     }
10540     // check similarity of elements of the sides
10541     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10542       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10543       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10544         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10545       }
10546       else {
10547         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10548       }
10549     }
10550
10551     // set nodes to merge
10552     // -------------------
10553
10554     if ( face[0] && face[1] )  {
10555       if ( nbNodes[0] != nbNodes[1] ) {
10556         MESSAGE("Diff nb of face nodes");
10557         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10558       }
10559 #ifdef DEBUG_MATCHING_NODES
10560       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10561                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10562                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10563 #endif
10564       int nbN = nbNodes[0];
10565       {
10566         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10567         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10568         for ( int i = 0 ; i < nbN - 2; ++i ) {
10569 #ifdef DEBUG_MATCHING_NODES
10570           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10571 #endif
10572           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10573         }
10574       }
10575
10576       // add other links of the face 1 to linkList
10577       // -----------------------------------------
10578
10579       const SMDS_MeshElement* f0 = face[0];
10580       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10581       for ( int i = 0; i < nbN; i++ )
10582       {
10583         const SMDS_MeshNode* n2 = f0->GetNode( i );
10584         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10585           linkSet.insert( SMESH_TLink( n1, n2 ));
10586         if ( !iter_isnew.second ) { // already in a set: no need to process
10587           linkSet.erase( iter_isnew.first );
10588         }
10589         else // new in set == encountered for the first time: add
10590         {
10591 #ifdef DEBUG_MATCHING_NODES
10592           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10593                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10594 #endif
10595           linkList[0].push_back ( NLink( n1, n2 ));
10596           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10597         }
10598         n1 = n2;
10599       }
10600     } // 2 faces found
10601   } // loop on link lists
10602
10603   return SEW_OK;
10604 }
10605
10606 //================================================================================
10607 /*!
10608   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10609   \param theElems - the list of elements (edges or faces) to be replicated
10610   The nodes for duplication could be found from these elements
10611   \param theNodesNot - list of nodes to NOT replicate
10612   \param theAffectedElems - the list of elements (cells and edges) to which the 
10613   replicated nodes should be associated to.
10614   \return TRUE if operation has been completed successfully, FALSE otherwise
10615 */
10616 //================================================================================
10617
10618 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10619                                     const TIDSortedElemSet& theNodesNot,
10620                                     const TIDSortedElemSet& theAffectedElems )
10621 {
10622   myLastCreatedElems.Clear();
10623   myLastCreatedNodes.Clear();
10624
10625   if ( theElems.size() == 0 )
10626     return false;
10627
10628   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10629   if ( !aMeshDS )
10630     return false;
10631
10632   bool res = false;
10633   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10634   // duplicate elements and nodes
10635   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10636   // replce nodes by duplications
10637   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10638   return res;
10639 }
10640
10641 //================================================================================
10642 /*!
10643   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10644   \param theMeshDS - mesh instance
10645   \param theElems - the elements replicated or modified (nodes should be changed)
10646   \param theNodesNot - nodes to NOT replicate
10647   \param theNodeNodeMap - relation of old node to new created node
10648   \param theIsDoubleElem - flag os to replicate element or modify
10649   \return TRUE if operation has been completed successfully, FALSE otherwise
10650 */
10651 //================================================================================
10652
10653 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10654                                     const TIDSortedElemSet& theElems,
10655                                     const TIDSortedElemSet& theNodesNot,
10656                                     std::map< const SMDS_MeshNode*,
10657                                     const SMDS_MeshNode* >& theNodeNodeMap,
10658                                     const bool theIsDoubleElem )
10659 {
10660   MESSAGE("doubleNodes");
10661   // iterate on through element and duplicate them (by nodes duplication)
10662   bool res = false;
10663   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10664   for ( ;  elemItr != theElems.end(); ++elemItr )
10665   {
10666     const SMDS_MeshElement* anElem = *elemItr;
10667     if (!anElem)
10668       continue;
10669
10670     bool isDuplicate = false;
10671     // duplicate nodes to duplicate element
10672     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10673     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10674     int ind = 0;
10675     while ( anIter->more() ) 
10676     { 
10677
10678       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10679       SMDS_MeshNode* aNewNode = aCurrNode;
10680       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10681         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10682       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10683       {
10684         // duplicate node
10685         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10686         theNodeNodeMap[ aCurrNode ] = aNewNode;
10687         myLastCreatedNodes.Append( aNewNode );
10688       }
10689       isDuplicate |= (aCurrNode != aNewNode);
10690       newNodes[ ind++ ] = aNewNode;
10691     }
10692     if ( !isDuplicate )
10693       continue;
10694
10695     if ( theIsDoubleElem )
10696       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10697     else
10698       {
10699       MESSAGE("ChangeElementNodes");
10700       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10701       }
10702     res = true;
10703   }
10704   return res;
10705 }
10706
10707 //================================================================================
10708 /*!
10709   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10710   \param theNodes - identifiers of nodes to be doubled
10711   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10712          nodes. If list of element identifiers is empty then nodes are doubled but 
10713          they not assigned to elements
10714   \return TRUE if operation has been completed successfully, FALSE otherwise
10715 */
10716 //================================================================================
10717
10718 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10719                                     const std::list< int >& theListOfModifiedElems )
10720 {
10721   MESSAGE("DoubleNodes");
10722   myLastCreatedElems.Clear();
10723   myLastCreatedNodes.Clear();
10724
10725   if ( theListOfNodes.size() == 0 )
10726     return false;
10727
10728   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10729   if ( !aMeshDS )
10730     return false;
10731
10732   // iterate through nodes and duplicate them
10733
10734   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10735
10736   std::list< int >::const_iterator aNodeIter;
10737   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10738   {
10739     int aCurr = *aNodeIter;
10740     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10741     if ( !aNode )
10742       continue;
10743
10744     // duplicate node
10745
10746     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10747     if ( aNewNode )
10748     {
10749       anOldNodeToNewNode[ aNode ] = aNewNode;
10750       myLastCreatedNodes.Append( aNewNode );
10751     }
10752   }
10753
10754   // Create map of new nodes for modified elements
10755
10756   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10757
10758   std::list< int >::const_iterator anElemIter;
10759   for ( anElemIter = theListOfModifiedElems.begin(); 
10760         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10761   {
10762     int aCurr = *anElemIter;
10763     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10764     if ( !anElem )
10765       continue;
10766
10767     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10768
10769     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10770     int ind = 0;
10771     while ( anIter->more() ) 
10772     { 
10773       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10774       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10775       {
10776         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10777         aNodeArr[ ind++ ] = aNewNode;
10778       }
10779       else
10780         aNodeArr[ ind++ ] = aCurrNode;
10781     }
10782     anElemToNodes[ anElem ] = aNodeArr;
10783   }
10784
10785   // Change nodes of elements  
10786
10787   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10788     anElemToNodesIter = anElemToNodes.begin();
10789   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10790   {
10791     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10792     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10793     if ( anElem )
10794       {
10795       MESSAGE("ChangeElementNodes");
10796       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10797       }
10798   }
10799
10800   return true;
10801 }
10802
10803 namespace {
10804
10805   //================================================================================
10806   /*!
10807   \brief Check if element located inside shape
10808   \return TRUE if IN or ON shape, FALSE otherwise
10809   */
10810   //================================================================================
10811
10812   template<class Classifier>
10813   bool isInside(const SMDS_MeshElement* theElem,
10814                 Classifier&             theClassifier,
10815                 const double            theTol)
10816   {
10817     gp_XYZ centerXYZ (0, 0, 0);
10818     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10819     while (aNodeItr->more())
10820       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10821
10822     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10823     theClassifier.Perform(aPnt, theTol);
10824     TopAbs_State aState = theClassifier.State();
10825     return (aState == TopAbs_IN || aState == TopAbs_ON );
10826   }
10827
10828   //================================================================================
10829   /*!
10830    * \brief Classifier of the 3D point on the TopoDS_Face
10831    *        with interaface suitable for isInside()
10832    */
10833   //================================================================================
10834
10835   struct _FaceClassifier
10836   {
10837     Extrema_ExtPS       _extremum;
10838     BRepAdaptor_Surface _surface;
10839     TopAbs_State        _state;
10840
10841     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10842     {
10843       _extremum.Initialize( _surface,
10844                             _surface.FirstUParameter(), _surface.LastUParameter(),
10845                             _surface.FirstVParameter(), _surface.LastVParameter(),
10846                             _surface.Tolerance(), _surface.Tolerance() );
10847     }
10848     void Perform(const gp_Pnt& aPnt, double theTol)
10849     {
10850       _state = TopAbs_OUT;
10851       _extremum.Perform(aPnt);
10852       if ( _extremum.IsDone() )
10853         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10854 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
10855           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10856 #else
10857           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10858 #endif
10859     }
10860     TopAbs_State State() const
10861     {
10862       return _state;
10863     }
10864   };
10865 }
10866
10867 //================================================================================
10868 /*!
10869   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10870   \param theElems - group of of elements (edges or faces) to be replicated
10871   \param theNodesNot - group of nodes not to replicate
10872   \param theShape - shape to detect affected elements (element which geometric center
10873   located on or inside shape).
10874   The replicated nodes should be associated to affected elements.
10875   \return TRUE if operation has been completed successfully, FALSE otherwise
10876 */
10877 //================================================================================
10878
10879 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10880                                             const TIDSortedElemSet& theNodesNot,
10881                                             const TopoDS_Shape&     theShape )
10882 {
10883   if ( theShape.IsNull() )
10884     return false;
10885
10886   const double aTol = Precision::Confusion();
10887   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10888   auto_ptr<_FaceClassifier>              aFaceClassifier;
10889   if ( theShape.ShapeType() == TopAbs_SOLID )
10890   {
10891     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10892     bsc3d->PerformInfinitePoint(aTol);
10893   }
10894   else if (theShape.ShapeType() == TopAbs_FACE )
10895   {
10896     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10897   }
10898
10899   // iterates on indicated elements and get elements by back references from their nodes
10900   TIDSortedElemSet anAffected;
10901   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10902   for ( ;  elemItr != theElems.end(); ++elemItr )
10903   {
10904     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10905     if (!anElem)
10906       continue;
10907
10908     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10909     while ( nodeItr->more() )
10910     {
10911       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10912       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10913         continue;
10914       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10915       while ( backElemItr->more() )
10916       {
10917         const SMDS_MeshElement* curElem = backElemItr->next();
10918         if ( curElem && theElems.find(curElem) == theElems.end() &&
10919              ( bsc3d.get() ?
10920                isInside( curElem, *bsc3d, aTol ) :
10921                isInside( curElem, *aFaceClassifier, aTol )))
10922           anAffected.insert( curElem );
10923       }
10924     }
10925   }
10926   return DoubleNodes( theElems, theNodesNot, anAffected );
10927 }
10928
10929 /*!
10930  *  \brief compute an oriented angle between two planes defined by four points.
10931  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10932  *  @param p0 base of the rotation axe
10933  *  @param p1 extremity of the rotation axe
10934  *  @param g1 belongs to the first plane
10935  *  @param g2 belongs to the second plane
10936  */
10937 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10938 {
10939 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10940 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10941 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10942 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10943   gp_Vec vref(p0, p1);
10944   gp_Vec v1(p0, g1);
10945   gp_Vec v2(p0, g2);
10946   gp_Vec n1 = vref.Crossed(v1);
10947   gp_Vec n2 = vref.Crossed(v2);
10948   return n2.AngleWithRef(n1, vref);
10949 }
10950
10951 /*!
10952  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10953  * The list of groups must describe a partition of the mesh volumes.
10954  * The nodes of the internal faces at the boundaries of the groups are doubled.
10955  * In option, the internal faces are replaced by flat elements.
10956  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10957  * The flat elements are stored in groups of volumes.
10958  * @param theElems - list of groups of volumes, where a group of volume is a set of
10959  * SMDS_MeshElements sorted by Id.
10960  * @param createJointElems - if TRUE, create the elements
10961  * @return TRUE if operation has been completed successfully, FALSE otherwise
10962  */
10963 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10964                                                      bool createJointElems)
10965 {
10966   MESSAGE("----------------------------------------------");
10967   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10968   MESSAGE("----------------------------------------------");
10969
10970   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10971   meshDS->BuildDownWardConnectivity(true);
10972   CHRONO(50);
10973   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10974
10975   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10976   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10977   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10978
10979   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10980   std::map<int,int>celldom; // cell vtkId --> domain
10981   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10982   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10983   faceDomains.clear();
10984   celldom.clear();
10985   cellDomains.clear();
10986   nodeDomains.clear();
10987   std::map<int,int> emptyMap;
10988   std::set<int> emptySet;
10989   emptyMap.clear();
10990
10991   for (int idom = 0; idom < theElems.size(); idom++)
10992     {
10993
10994       // --- build a map (face to duplicate --> volume to modify)
10995       //     with all the faces shared by 2 domains (group of elements)
10996       //     and corresponding volume of this domain, for each shared face.
10997       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10998
10999       //MESSAGE("Domain " << idom);
11000       const TIDSortedElemSet& domain = theElems[idom];
11001       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11002       for (; elemItr != domain.end(); ++elemItr)
11003         {
11004           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11005           if (!anElem)
11006             continue;
11007           int vtkId = anElem->getVtkId();
11008           //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
11009           int neighborsVtkIds[NBMAXNEIGHBORS];
11010           int downIds[NBMAXNEIGHBORS];
11011           unsigned char downTypes[NBMAXNEIGHBORS];
11012           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11013           for (int n = 0; n < nbNeighbors; n++)
11014             {
11015               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
11016               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11017               if (! domain.count(elem)) // neighbor is in another domain : face is shared
11018                 {
11019                   DownIdType face(downIds[n], downTypes[n]);
11020                   if (!faceDomains.count(face))
11021                     faceDomains[face] = emptyMap; // create an empty entry for face
11022                   if (!faceDomains[face].count(idom))
11023                     {
11024                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
11025                       celldom[vtkId] = idom;
11026                       //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
11027                     }
11028                 }
11029             }
11030         }
11031     }
11032
11033   //MESSAGE("Number of shared faces " << faceDomains.size());
11034   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
11035
11036   // --- explore the shared faces domain by domain,
11037   //     explore the nodes of the face and see if they belong to a cell in the domain,
11038   //     which has only a node or an edge on the border (not a shared face)
11039
11040   for (int idomain = 0; idomain < theElems.size(); idomain++)
11041     {
11042       //MESSAGE("Domain " << idomain);
11043       const TIDSortedElemSet& domain = theElems[idomain];
11044       itface = faceDomains.begin();
11045       for (; itface != faceDomains.end(); ++itface)
11046         {
11047           std::map<int, int> domvol = itface->second;
11048           if (!domvol.count(idomain))
11049             continue;
11050           DownIdType face = itface->first;
11051           //MESSAGE(" --- face " << face.cellId);
11052           std::set<int> oldNodes;
11053           oldNodes.clear();
11054           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11055           std::set<int>::iterator itn = oldNodes.begin();
11056           for (; itn != oldNodes.end(); ++itn)
11057             {
11058               int oldId = *itn;
11059               //MESSAGE("     node " << oldId);
11060               std::set<int> cells;
11061               cells.clear();
11062               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11063               for (int i=0; i<l.ncells; i++)
11064                 {
11065                   int vtkId = l.cells[i];
11066                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
11067                   if (!domain.count(anElem))
11068                     continue;
11069                   int vtkType = grid->GetCellType(vtkId);
11070                   int downId = grid->CellIdToDownId(vtkId);
11071                   if (downId < 0)
11072                     {
11073                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
11074                       continue; // not OK at this stage of the algorithm:
11075                                 //no cells created after BuildDownWardConnectivity
11076                     }
11077                   DownIdType aCell(downId, vtkType);
11078                   if (celldom.count(vtkId))
11079                     continue;
11080                   cellDomains[aCell][idomain] = vtkId;
11081                   celldom[vtkId] = idomain;
11082                   //MESSAGE("       cell " << vtkId << " domain " << idomain);
11083                 }
11084             }
11085         }
11086     }
11087
11088   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
11089   //     for each shared face, get the nodes
11090   //     for each node, for each domain of the face, create a clone of the node
11091
11092   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
11093   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
11094   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
11095
11096   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
11097   std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
11098   std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
11099
11100   for (int idomain = 0; idomain < theElems.size(); idomain++)
11101     {
11102       itface = faceDomains.begin();
11103       for (; itface != faceDomains.end(); ++itface)
11104         {
11105           std::map<int, int> domvol = itface->second;
11106           if (!domvol.count(idomain))
11107             continue;
11108           DownIdType face = itface->first;
11109           //MESSAGE(" --- face " << face.cellId);
11110           std::set<int> oldNodes;
11111           oldNodes.clear();
11112           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11113           bool isMultipleDetected = false;
11114           std::set<int>::iterator itn = oldNodes.begin();
11115           for (; itn != oldNodes.end(); ++itn)
11116             {
11117               int oldId = *itn;
11118               //MESSAGE("     node " << oldId);
11119               if (!nodeDomains.count(oldId))
11120                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11121               if (nodeDomains[oldId].empty())
11122                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11123               std::map<int, int>::iterator itdom = domvol.begin();
11124               for (; itdom != domvol.end(); ++itdom)
11125                 {
11126                   int idom = itdom->first;
11127                   //MESSAGE("         domain " << idom);
11128                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
11129                     {
11130                       if (nodeDomains[oldId].size() >= 2) // a multiple node
11131                         {
11132                           vector<int> orderedDoms;
11133                           //MESSAGE("multiple node " << oldId);
11134                           isMultipleDetected =true;
11135                           if (mutipleNodes.count(oldId))
11136                             orderedDoms = mutipleNodes[oldId];
11137                           else
11138                             {
11139                               map<int,int>::iterator it = nodeDomains[oldId].begin();
11140                               for (; it != nodeDomains[oldId].end(); ++it)
11141                                 orderedDoms.push_back(it->first);
11142                             }
11143                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
11144                           //stringstream txt;
11145                           //for (int i=0; i<orderedDoms.size(); i++)
11146                           //  txt << orderedDoms[i] << " ";
11147                           //MESSAGE("orderedDoms " << txt.str());
11148                           mutipleNodes[oldId] = orderedDoms;
11149                         }
11150                       double *coords = grid->GetPoint(oldId);
11151                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11152                       int newId = newNode->getVtkId();
11153                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
11154                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11155                     }
11156                   if (nodeDomains[oldId].size() >= 3)
11157                     {
11158                       //MESSAGE("confirm multiple node " << oldId);
11159                       isMultipleDetected =true;
11160                     }
11161                 }
11162             }
11163           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11164             {
11165               //MESSAGE("multiple Nodes detected on a shared face");
11166               int downId = itface->first.cellId;
11167               unsigned char cellType = itface->first.cellType;
11168               // --- shared edge or shared face ?
11169               if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
11170                 {
11171                   int nodes[3];
11172                   int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
11173                   for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
11174                     if (mutipleNodes.count(nodes[i]))
11175                       if (!mutipleNodesToFace.count(nodes[i]))
11176                         mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
11177                }
11178               else // shared face (between two volumes)
11179                 {
11180                   int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11181                   const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11182                   const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11183                   for (int ie =0; ie < nbEdges; ie++)
11184                     {
11185                       int nodes[3];
11186                       int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11187                       if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11188                         {
11189                           vector<int> vn0 = mutipleNodes[nodes[0]];
11190                           vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11191                           sort( vn0.begin(), vn0.end() );
11192                           sort( vn1.begin(), vn1.end() );
11193                           if (vn0 == vn1)
11194                             {
11195                               //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11196                               double *coords = grid->GetPoint(nodes[0]);
11197                               gp_Pnt p0(coords[0], coords[1], coords[2]);
11198                               coords = grid->GetPoint(nodes[nbNodes - 1]);
11199                               gp_Pnt p1(coords[0], coords[1], coords[2]);
11200                               gp_Pnt gref;
11201                               int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11202                               map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11203                               map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11204                               int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11205                               for (int id=0; id < vn0.size(); id++)
11206                                 {
11207                                   int idom = vn0[id];
11208                                   for (int ivol=0; ivol<nbvol; ivol++)
11209                                     {
11210                                       int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11211                                       SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11212                                       if (theElems[idom].count(elem))
11213                                         {
11214                                           SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11215                                           domvol[idom] = svol;
11216                                           //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11217                                           double values[3];
11218                                           vtkIdType npts = 0;
11219                                           vtkIdType* pts = 0;
11220                                           grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11221                                           SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11222                                           if (id ==0)
11223                                             {
11224                                               gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11225                                               angleDom[idom] = 0;
11226                                             }
11227                                           else
11228                                             {
11229                                               gp_Pnt g(values[0], values[1], values[2]);
11230                                               angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11231                                               //MESSAGE("  angle=" << angleDom[idom]);
11232                                             }
11233                                           break;
11234                                         }
11235                                     }
11236                                 }
11237                               map<double, int> sortedDom; // sort domains by angle
11238                               for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11239                                 sortedDom[ia->second] = ia->first;
11240                               vector<int> vnodes;
11241                               vector<int> vdom;
11242                               for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11243                                 {
11244                                   vdom.push_back(ib->second);
11245                                   //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11246                                 }
11247                               for (int ino = 0; ino < nbNodes; ino++)
11248                                 vnodes.push_back(nodes[ino]);
11249                               edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11250                             }
11251                         }
11252                     }
11253                 }
11254             }
11255         }
11256     }
11257
11258   // --- iterate on shared faces (volumes to modify, face to extrude)
11259   //     get node id's of the face (id SMDS = id VTK)
11260   //     create flat element with old and new nodes if requested
11261
11262   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11263   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11264
11265   std::map<int, std::map<long,int> > nodeQuadDomains;
11266   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11267
11268   if (createJointElems)
11269     {
11270       itface = faceDomains.begin();
11271       for (; itface != faceDomains.end(); ++itface)
11272         {
11273           DownIdType face = itface->first;
11274           std::set<int> oldNodes;
11275           std::set<int>::iterator itn;
11276           oldNodes.clear();
11277           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11278
11279           std::map<int, int> domvol = itface->second;
11280           std::map<int, int>::iterator itdom = domvol.begin();
11281           int dom1 = itdom->first;
11282           int vtkVolId = itdom->second;
11283           itdom++;
11284           int dom2 = itdom->first;
11285           SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11286                                                              nodeQuadDomains);
11287           stringstream grpname;
11288           grpname << "j_";
11289           if (dom1 < dom2)
11290             grpname << dom1 << "_" << dom2;
11291           else
11292             grpname << dom2 << "_" << dom1;
11293           int idg;
11294           string namegrp = grpname.str();
11295           if (!mapOfJunctionGroups.count(namegrp))
11296             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
11297           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11298           if (sgrp)
11299             sgrp->Add(vol->GetID());
11300         }
11301     }
11302
11303   // --- create volumes on multiple domain intersection if requested
11304   //     iterate on mutipleNodesToFace
11305   //     iterate on edgesMultiDomains
11306
11307   if (createJointElems)
11308     {
11309       // --- iterate on mutipleNodesToFace
11310
11311       std::map<int, std::vector<int> >::iterator itn =  mutipleNodesToFace.begin();
11312       for (; itn != mutipleNodesToFace.end(); ++itn)
11313         {
11314           int node = itn->first;
11315           vector<int> orderDom = itn->second;
11316           vector<vtkIdType> orderedNodes;
11317           for (int idom = 0; idom <orderDom.size(); idom++)
11318             orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
11319             SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
11320
11321             stringstream grpname;
11322             grpname << "m2j_";
11323             grpname << 0 << "_" << 0;
11324             int idg;
11325             string namegrp = grpname.str();
11326             if (!mapOfJunctionGroups.count(namegrp))
11327               mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
11328             SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11329             if (sgrp)
11330               sgrp->Add(face->GetID());
11331         }
11332
11333       // --- iterate on edgesMultiDomains
11334
11335       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11336       for (; ite != edgesMultiDomains.end(); ++ite)
11337         {
11338           vector<int> nodes = ite->first;
11339           vector<int> orderDom = ite->second;
11340           vector<vtkIdType> orderedNodes;
11341           if (nodes.size() == 2)
11342             {
11343               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11344               for (int ino=0; ino < nodes.size(); ino++)
11345                 if (orderDom.size() == 3)
11346                   for (int idom = 0; idom <orderDom.size(); idom++)
11347                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11348                 else
11349                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11350                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11351               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11352
11353               stringstream grpname;
11354               grpname << "mj_";
11355               grpname << 0 << "_" << 0;
11356               int idg;
11357               string namegrp = grpname.str();
11358               if (!mapOfJunctionGroups.count(namegrp))
11359                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11360               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11361               if (sgrp)
11362                 sgrp->Add(vol->GetID());
11363             }
11364           else
11365             {
11366               MESSAGE("Quadratic multiple joints not implemented");
11367               // TODO quadratic nodes
11368             }
11369         }
11370     }
11371
11372   // --- list the explicit faces and edges of the mesh that need to be modified,
11373   //     i.e. faces and edges built with one or more duplicated nodes.
11374   //     associate these faces or edges to their corresponding domain.
11375   //     only the first domain found is kept when a face or edge is shared
11376
11377   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11378   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11379   faceOrEdgeDom.clear();
11380   feDom.clear();
11381
11382   for (int idomain = 0; idomain < theElems.size(); idomain++)
11383     {
11384       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11385       for (; itnod != nodeDomains.end(); ++itnod)
11386         {
11387           int oldId = itnod->first;
11388           //MESSAGE("     node " << oldId);
11389           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11390           for (int i = 0; i < l.ncells; i++)
11391             {
11392               int vtkId = l.cells[i];
11393               int vtkType = grid->GetCellType(vtkId);
11394               int downId = grid->CellIdToDownId(vtkId);
11395               if (downId < 0)
11396                 continue; // new cells: not to be modified
11397               DownIdType aCell(downId, vtkType);
11398               int volParents[1000];
11399               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11400               for (int j = 0; j < nbvol; j++)
11401                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11402                   if (!feDom.count(vtkId))
11403                     {
11404                       feDom[vtkId] = idomain;
11405                       faceOrEdgeDom[aCell] = emptyMap;
11406                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11407                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11408                       //        << " type " << vtkType << " downId " << downId);
11409                     }
11410             }
11411         }
11412     }
11413
11414   // --- iterate on shared faces (volumes to modify, face to extrude)
11415   //     get node id's of the face
11416   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11417
11418   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11419   for (int m=0; m<3; m++)
11420     {
11421       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11422       itface = (*amap).begin();
11423       for (; itface != (*amap).end(); ++itface)
11424         {
11425           DownIdType face = itface->first;
11426           std::set<int> oldNodes;
11427           std::set<int>::iterator itn;
11428           oldNodes.clear();
11429           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11430           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11431           std::map<int, int> localClonedNodeIds;
11432
11433           std::map<int, int> domvol = itface->second;
11434           std::map<int, int>::iterator itdom = domvol.begin();
11435           for (; itdom != domvol.end(); ++itdom)
11436             {
11437               int idom = itdom->first;
11438               int vtkVolId = itdom->second;
11439               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11440               localClonedNodeIds.clear();
11441               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11442                 {
11443                   int oldId = *itn;
11444                   if (nodeDomains[oldId].count(idom))
11445                     {
11446                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11447                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11448                     }
11449                 }
11450               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11451             }
11452         }
11453     }
11454
11455   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11456   grid->BuildLinks();
11457
11458   CHRONOSTOP(50);
11459   counters::stats();
11460   return true;
11461 }
11462
11463 /*!
11464  * \brief Double nodes on some external faces and create flat elements.
11465  * Flat elements are mainly used by some types of mechanic calculations.
11466  *
11467  * Each group of the list must be constituted of faces.
11468  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11469  * @param theElems - list of groups of faces, where a group of faces is a set of
11470  * SMDS_MeshElements sorted by Id.
11471  * @return TRUE if operation has been completed successfully, FALSE otherwise
11472  */
11473 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11474 {
11475   MESSAGE("-------------------------------------------------");
11476   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11477   MESSAGE("-------------------------------------------------");
11478
11479   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11480
11481   // --- For each group of faces
11482   //     duplicate the nodes, create a flat element based on the face
11483   //     replace the nodes of the faces by their clones
11484
11485   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11486   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11487   clonedNodes.clear();
11488   intermediateNodes.clear();
11489   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11490   mapOfJunctionGroups.clear();
11491
11492   for (int idom = 0; idom < theElems.size(); idom++)
11493     {
11494       const TIDSortedElemSet& domain = theElems[idom];
11495       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11496       for (; elemItr != domain.end(); ++elemItr)
11497         {
11498           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11499           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11500           if (!aFace)
11501             continue;
11502           // MESSAGE("aFace=" << aFace->GetID());
11503           bool isQuad = aFace->IsQuadratic();
11504           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11505
11506           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11507
11508           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11509           while (nodeIt->more())
11510             {
11511               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11512               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11513               if (isMedium)
11514                 ln2.push_back(node);
11515               else
11516                 ln0.push_back(node);
11517
11518               const SMDS_MeshNode* clone = 0;
11519               if (!clonedNodes.count(node))
11520                 {
11521                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11522                   clonedNodes[node] = clone;
11523                 }
11524               else
11525                 clone = clonedNodes[node];
11526
11527               if (isMedium)
11528                 ln3.push_back(clone);
11529               else
11530                 ln1.push_back(clone);
11531
11532               const SMDS_MeshNode* inter = 0;
11533               if (isQuad && (!isMedium))
11534                 {
11535                   if (!intermediateNodes.count(node))
11536                     {
11537                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11538                       intermediateNodes[node] = inter;
11539                     }
11540                   else
11541                     inter = intermediateNodes[node];
11542                   ln4.push_back(inter);
11543                 }
11544             }
11545
11546           // --- extrude the face
11547
11548           vector<const SMDS_MeshNode*> ln;
11549           SMDS_MeshVolume* vol = 0;
11550           vtkIdType aType = aFace->GetVtkType();
11551           switch (aType)
11552           {
11553             case VTK_TRIANGLE:
11554               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11555               // MESSAGE("vol prism " << vol->GetID());
11556               ln.push_back(ln1[0]);
11557               ln.push_back(ln1[1]);
11558               ln.push_back(ln1[2]);
11559               break;
11560             case VTK_QUAD:
11561               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11562               // MESSAGE("vol hexa " << vol->GetID());
11563               ln.push_back(ln1[0]);
11564               ln.push_back(ln1[1]);
11565               ln.push_back(ln1[2]);
11566               ln.push_back(ln1[3]);
11567               break;
11568             case VTK_QUADRATIC_TRIANGLE:
11569               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11570                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11571               // MESSAGE("vol quad prism " << vol->GetID());
11572               ln.push_back(ln1[0]);
11573               ln.push_back(ln1[1]);
11574               ln.push_back(ln1[2]);
11575               ln.push_back(ln3[0]);
11576               ln.push_back(ln3[1]);
11577               ln.push_back(ln3[2]);
11578               break;
11579             case VTK_QUADRATIC_QUAD:
11580 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11581 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11582 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11583               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11584                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11585                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11586               // MESSAGE("vol quad hexa " << vol->GetID());
11587               ln.push_back(ln1[0]);
11588               ln.push_back(ln1[1]);
11589               ln.push_back(ln1[2]);
11590               ln.push_back(ln1[3]);
11591               ln.push_back(ln3[0]);
11592               ln.push_back(ln3[1]);
11593               ln.push_back(ln3[2]);
11594               ln.push_back(ln3[3]);
11595               break;
11596             case VTK_POLYGON:
11597               break;
11598             default:
11599               break;
11600           }
11601
11602           if (vol)
11603             {
11604               stringstream grpname;
11605               grpname << "jf_";
11606               grpname << idom;
11607               int idg;
11608               string namegrp = grpname.str();
11609               if (!mapOfJunctionGroups.count(namegrp))
11610                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11611               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11612               if (sgrp)
11613                 sgrp->Add(vol->GetID());
11614             }
11615
11616           // --- modify the face
11617
11618           aFace->ChangeNodes(&ln[0], ln.size());
11619         }
11620     }
11621   return true;
11622 }
11623
11624 //================================================================================
11625 /*!
11626  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11627  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11628  * \return TRUE if operation has been completed successfully, FALSE otherwise
11629  */
11630 //================================================================================
11631
11632 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11633 {
11634   // iterates on volume elements and detect all free faces on them
11635   SMESHDS_Mesh* aMesh = GetMeshDS();
11636   if (!aMesh)
11637     return false;
11638   //bool res = false;
11639   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11640   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11641   while(vIt->more())
11642   {
11643     const SMDS_MeshVolume* volume = vIt->next();
11644     SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
11645     vTool.SetExternalNormal();
11646     //const bool isPoly = volume->IsPoly();
11647     const int iQuad = volume->IsQuadratic();
11648     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11649     {
11650       if (!vTool.IsFreeFace(iface))
11651         continue;
11652       nbFree++;
11653       vector<const SMDS_MeshNode *> nodes;
11654       int nbFaceNodes = vTool.NbFaceNodes(iface);
11655       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11656       int inode = 0;
11657       for ( ; inode < nbFaceNodes; inode += iQuad+1)
11658         nodes.push_back(faceNodes[inode]);
11659       if (iQuad) { // add medium nodes
11660         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11661           nodes.push_back(faceNodes[inode]);
11662         if ( nbFaceNodes == 9 ) // bi-quadratic quad
11663           nodes.push_back(faceNodes[8]);
11664       }
11665       // add new face based on volume nodes
11666       if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
11667         nbExisted++;
11668         continue; // face already exsist
11669       }
11670       AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
11671       nbCreated++;
11672     }
11673   }
11674   return ( nbFree==(nbExisted+nbCreated) );
11675 }
11676
11677 namespace
11678 {
11679   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11680   {
11681     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11682       return n;
11683     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11684   }
11685 }
11686 //================================================================================
11687 /*!
11688  * \brief Creates missing boundary elements
11689  *  \param elements - elements whose boundary is to be checked
11690  *  \param dimension - defines type of boundary elements to create
11691  *  \param group - a group to store created boundary elements in
11692  *  \param targetMesh - a mesh to store created boundary elements in
11693  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11694  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
11695  *                                boundary elements will be copied into the targetMesh
11696  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11697  *                                boundary elements will be added into the new group
11698  *  \param aroundElements - if true, elements will be created on boundary of given
11699  *                          elements else, on boundary of the whole mesh.
11700  * \return nb of added boundary elements
11701  */
11702 //================================================================================
11703
11704 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11705                                        Bnd_Dimension           dimension,
11706                                        SMESH_Group*            group/*=0*/,
11707                                        SMESH_Mesh*             targetMesh/*=0*/,
11708                                        bool                    toCopyElements/*=false*/,
11709                                        bool                    toCopyExistingBoundary/*=false*/,
11710                                        bool                    toAddExistingBondary/*= false*/,
11711                                        bool                    aroundElements/*= false*/)
11712 {
11713   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11714   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11715   // hope that all elements are of the same type, do not check them all
11716   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11717     throw SALOME_Exception(LOCALIZED("wrong element type"));
11718
11719   if ( !targetMesh )
11720     toCopyElements = toCopyExistingBoundary = false;
11721
11722   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11723   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11724   int nbAddedBnd = 0;
11725
11726   // editor adding present bnd elements and optionally holding elements to add to the group
11727   SMESH_MeshEditor* presentEditor;
11728   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11729   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11730
11731   SMESH_MesherHelper helper( *myMesh );
11732   const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
11733   SMDS_VolumeTool vTool;
11734   TIDSortedElemSet avoidSet;
11735   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11736   int inode;
11737
11738   typedef vector<const SMDS_MeshNode*> TConnectivity;
11739
11740   SMDS_ElemIteratorPtr eIt;
11741   if (elements.empty())
11742     eIt = aMesh->elementsIterator(elemType);
11743   else
11744     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11745
11746   while (eIt->more())
11747   {
11748     const SMDS_MeshElement* elem = eIt->next();
11749     const int iQuad = elem->IsQuadratic();
11750
11751     // ------------------------------------------------------------------------------------
11752     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11753     // ------------------------------------------------------------------------------------
11754     vector<const SMDS_MeshElement*> presentBndElems;
11755     vector<TConnectivity>           missingBndElems;
11756     TConnectivity nodes;
11757     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
11758     {
11759       vTool.SetExternalNormal();
11760       const SMDS_MeshElement* otherVol = 0;
11761       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11762       {
11763         if ( !vTool.IsFreeFace(iface, &otherVol) &&
11764              ( !aroundElements || elements.count( otherVol )))
11765           continue;
11766         const int nbFaceNodes = vTool.NbFaceNodes(iface);
11767         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11768         if ( missType == SMDSAbs_Edge ) // boundary edges
11769         {
11770           nodes.resize( 2+iQuad );
11771           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11772           {
11773             for ( int j = 0; j < nodes.size(); ++j )
11774               nodes[j] =nn[i+j];
11775             if ( const SMDS_MeshElement* edge =
11776                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11777               presentBndElems.push_back( edge );
11778             else
11779               missingBndElems.push_back( nodes );
11780           }
11781         }
11782         else // boundary face
11783         {
11784           nodes.clear();
11785           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11786             nodes.push_back( nn[inode] );
11787           if (iQuad) // add medium nodes
11788             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11789               nodes.push_back( nn[inode] );
11790           int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
11791           if ( iCenter > 0 )
11792             nodes.push_back( vTool.GetNodes()[ iCenter ] );
11793
11794           if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
11795                                                                SMDSAbs_Face, /*noMedium=*/false ))
11796             presentBndElems.push_back( f );
11797           else
11798             missingBndElems.push_back( nodes );
11799
11800           if ( targetMesh != myMesh )
11801           {
11802             // add 1D elements on face boundary to be added to a new mesh
11803             const SMDS_MeshElement* edge;
11804             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11805             {
11806               if ( iQuad )
11807                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11808               else
11809                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11810               if ( edge && avoidSet.insert( edge ).second )
11811                 presentBndElems.push_back( edge );
11812             }
11813           }
11814         }
11815       }
11816     }
11817     else                     // elem is a face ------------------------------------------
11818     {
11819       avoidSet.clear(), avoidSet.insert( elem );
11820       int nbNodes = elem->NbCornerNodes();
11821       nodes.resize( 2 /*+ iQuad*/);
11822       for ( int i = 0; i < nbNodes; i++ )
11823       {
11824         nodes[0] = elem->GetNode(i);
11825         nodes[1] = elem->GetNode((i+1)%nbNodes);
11826         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11827           continue; // not free link
11828
11829         //if ( iQuad )
11830         //nodes[2] = elem->GetNode( i + nbNodes );
11831         if ( const SMDS_MeshElement* edge =
11832              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11833           presentBndElems.push_back( edge );
11834         else
11835           missingBndElems.push_back( nodes );
11836       }
11837     }
11838
11839     // ---------------------------------
11840     // 2. Add missing boundary elements
11841     // ---------------------------------
11842     if ( targetMesh != myMesh )
11843       // instead of making a map of nodes in this mesh and targetMesh,
11844       // we create nodes with same IDs.
11845       for ( int i = 0; i < missingBndElems.size(); ++i )
11846       {
11847         TConnectivity& srcNodes = missingBndElems[i];
11848         TConnectivity  nodes( srcNodes.size() );
11849         for ( inode = 0; inode < nodes.size(); ++inode )
11850           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11851         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11852                                                                    missType,
11853                                                                    /*noMedium=*/false))
11854           continue;
11855         tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11856         ++nbAddedBnd;
11857       }
11858     else
11859       for ( int i = 0; i < missingBndElems.size(); ++i )
11860       {
11861         TConnectivity& nodes = missingBndElems[i];
11862         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11863                                                                    missType,
11864                                                                    /*noMedium=*/false))
11865           continue;
11866         SMDS_MeshElement* elem = 
11867           tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11868         ++nbAddedBnd;
11869
11870         // try to set a new element to a shape
11871         if ( myMesh->HasShapeToMesh() )
11872         {
11873           bool ok = true;
11874           set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
11875           const int nbN = nodes.size() / (iQuad+1 );
11876           for ( inode = 0; inode < nbN && ok; ++inode )
11877           {
11878             pair<int, TopAbs_ShapeEnum> i_stype =
11879               helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
11880             if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
11881               mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
11882           }
11883           if ( ok && mediumShapes.size() > 1 )
11884           {
11885             set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
11886             pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
11887             for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
11888             {
11889               if (( ok = ( stype_i->first != stype_i_0.first )))
11890                 ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
11891                                         aMesh->IndexToShape( stype_i_0.second ));
11892             }
11893           }
11894           if ( ok && mediumShapes.begin()->first == missShapeType )
11895             aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
11896         }
11897       }
11898
11899     // ----------------------------------
11900     // 3. Copy present boundary elements
11901     // ----------------------------------
11902     if ( toCopyExistingBoundary )
11903       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11904       {
11905         const SMDS_MeshElement* e = presentBndElems[i];
11906         TConnectivity nodes( e->NbNodes() );
11907         for ( inode = 0; inode < nodes.size(); ++inode )
11908           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11909         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11910       }
11911     else // store present elements to add them to a group
11912       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11913       {
11914         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11915       }
11916       
11917   } // loop on given elements
11918
11919   // ---------------------------------------------
11920   // 4. Fill group with boundary elements
11921   // ---------------------------------------------
11922   if ( group )
11923   {
11924     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11925       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11926         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11927   }
11928   tgtEditor.myLastCreatedElems.Clear();
11929   tgtEditor2.myLastCreatedElems.Clear();
11930
11931   // -----------------------
11932   // 5. Copy given elements
11933   // -----------------------
11934   if ( toCopyElements && targetMesh != myMesh )
11935   {
11936     if (elements.empty())
11937       eIt = aMesh->elementsIterator(elemType);
11938     else
11939       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11940     while (eIt->more())
11941     {
11942       const SMDS_MeshElement* elem = eIt->next();
11943       TConnectivity nodes( elem->NbNodes() );
11944       for ( inode = 0; inode < nodes.size(); ++inode )
11945         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11946       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11947
11948       tgtEditor.myLastCreatedElems.Clear();
11949     }
11950   }
11951   return nbAddedBnd;
11952 }